From patchwork Thu Apr 26 15:29:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 10366207 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C0890601D3 for ; Thu, 26 Apr 2018 15:33:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A94BD2913C for ; Thu, 26 Apr 2018 15:33:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 953A2291D8; Thu, 26 Apr 2018 15:33:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0C0AE291AB for ; Thu, 26 Apr 2018 15:32:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=hk0p7GmsJRt6qnUwDvUdtz1Hiyrv0tj7QNwFIqgepY0=; b=ZPV9vSFuxzUq3B5GL/1IoLvGzU qlKkTQkldYDK3Y9FRy0t0GbiYM1T7rZD5YJUHVf8Eldgvv5Z4WaJ4+Llo/Mv2Lfn2e8RbxvyM2Go5 hWSsqjBUbZddcKaoJOG9yFG5LLyNCkT+AB/YEFjXVMrn3w4kiwSvOyNqeYuoVkQpVgZuYYejT41/E 314YpJ1FqF7icCHiHnxkW23TG8gA5XCeHnj8xE5p91lqFf+/z5Ro4RoaFYe4hPAcJCjp1JYYQCRzd xdqZ+pCgV2X/vS/iJ/6sa6uP1iQ6JjX2vNXk67kWdepyD5eKyb7elCHqYOEpkrTnNjXeOyS9e0vTJ kUfVnT1g==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fBisf-0001VL-9i; Thu, 26 Apr 2018 15:32:21 +0000 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fBiqD-0007Vq-5o for linux-arm-kernel@lists.infradead.org; Thu, 26 Apr 2018 15:29:56 +0000 Received: by mail-wm0-x241.google.com with SMTP id i3so14039551wmf.3 for ; Thu, 26 Apr 2018 08:29:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=dP/iv4nYZ2Zzzb9UJyIQSqixu5+U0vTlmCuWP8NrWuU=; b=A3JLp0eIPkKx5AgWXDao2lrg4+6/FMwTvhR+f1joZI9gK4uLL9p/14GBE1rsWvnd+I zGGgVLDBDatk1o03uvQMa8P/jy53q61oBWk/P3qA3Nap6O35NyVPGf4CQnmbKf7xNFfq x8p+N3nH+3JP1PIHvM+O2B+tOKsvVAmYLuNTjCzJl7GPI7SvTWefC1rbkZiTwB8TXAzB YixFkR3gK/wMG8Mo0W1sfGu5IeYBriW9lNZkFSEFxDphO0eImYwJR126DAszpJXYnuIQ 9vO+Q9KeyD4/yUfFWVW6OSuOvA2QTRe9vHP5hnKxE1/tmMpNXxRyjdhiTuqMwHJv1iMk VpEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=dP/iv4nYZ2Zzzb9UJyIQSqixu5+U0vTlmCuWP8NrWuU=; b=C6M+K2/S5s+PdHH31/VGfKaBmEBtdHdCAmQ2TjFQFNfbrXI90MZ4x6SldbMMK/j2Cw jj5IP4KqBNKw6p8gKVaik7d3klgNHf7M/xS3o/j1ZFpX5CbWfbrzhia9vTzgdSjoGiI8 5Uf5zJkEMOZQOA2CGVh1m2CGHvmtMIMv9NFbAw5F5fdVWwb1AXss8T9kQ+tKgXzcFKlT T17mX9GoPT5xieMgAieeRHTf1NgM4QYjYOQ81HEDb896hvBHh+iPIvh20RyZwHCjHu70 2rNOksAvE2r2yKJsdLA6SK+z66YiNgh2DBTAwAdtgxkw9VY0QvXN5A/oxHHLKqDrj22k FEiw== X-Gm-Message-State: ALQs6tCeZ4RlT1a09DD02j/rgvCWZrsjO+l8yj6OhSlZAVcXFdIfNKXJ 8/iFuzbMdSBAvVgUGdWDbOsZUA== X-Google-Smtp-Source: AIpwx4+3XoVfRcQwUo4VMIHmDgzM27k0T9z6t/d0xTO2i5eMbkLJJD3Sr/iGDnuXAA2L4GHUszRR+Q== X-Received: by 10.28.180.8 with SMTP id d8mr18665188wmf.48.1524756577140; Thu, 26 Apr 2018 08:29:37 -0700 (PDT) Received: from brgl-bgdev.lan (LFbn-NIC-1-84-58.w2-15.abo.wanadoo.fr. [2.15.173.58]) by smtp.gmail.com with ESMTPSA id q2-v6sm2679355wrj.57.2018.04.26.08.29.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 26 Apr 2018 08:29:36 -0700 (PDT) From: Bartosz Golaszewski To: Sekhar Nori , Kevin Hilman , David Lechner , Michael Turquette , Stephen Boyd , Arnd Bergmann , Greg Kroah-Hartman , Rob Herring , Mark Rutland , Yoshinori Sato , Rich Felker , Frank Rowand , "Rafael J . Wysocki" , Jarkko Sakkinen , Dmitry Torokhov , Arend van Spriel , Heikki Krogerus , Michal Suchanek , Jan Kiszka , Andy Shevchenko , Marc Zyngier , Peter Rosin Subject: [PATCH RFC PoC 1/2] earlydev: implement a new way to probe platform devices early Date: Thu, 26 Apr 2018 17:29:19 +0200 Message-Id: <20180426152920.21569-2-brgl@bgdev.pl> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180426152920.21569-1-brgl@bgdev.pl> References: <20180426152920.21569-1-brgl@bgdev.pl> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180426_082949_225357_E938487F X-CRM114-Status: GOOD ( 26.92 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Bartosz Golaszewski MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Bartosz Golaszewski The current implementation of early platform drivers is pretty much a hack built on top of the early_param mechanism. The devices only look like platform devices and use the same structures but never actually get registered with the driver model. The idea behind this series is to allow users to probe platform devices very early in the boot sequence and then switch the early devices to actual platform devices and the early drivers to platform drivers in during device_initcall. Signed-off-by: Bartosz Golaszewski --- drivers/base/Kconfig | 3 + drivers/base/Makefile | 1 + drivers/base/earlydev.c | 175 ++++++++++++++++++++++++++++++++ drivers/base/platform.c | 11 ++ include/linux/earlydev.h | 63 ++++++++++++ include/linux/platform_device.h | 4 + 6 files changed, 257 insertions(+) create mode 100644 drivers/base/earlydev.c create mode 100644 include/linux/earlydev.h diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 29b0eb452b3a..e05f96d626b3 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -170,6 +170,9 @@ config DEV_COREDUMP default y if WANT_DEV_COREDUMP depends on ALLOW_DEV_COREDUMP +config EARLYDEV + def_bool n + config DEBUG_DRIVER bool "Driver Core verbose debug messages" depends on DEBUG_KERNEL diff --git a/drivers/base/Makefile b/drivers/base/Makefile index b074f242a435..ec47f86eac44 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -7,6 +7,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ attribute_container.o transport_class.o \ topology.o container.o property.o cacheinfo.o \ devcon.o +obj-$(CONFIG_EARLYDEV) += earlydev.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-$(CONFIG_DMA_CMA) += dma-contiguous.o obj-y += power/ diff --git a/drivers/base/earlydev.c b/drivers/base/earlydev.c new file mode 100644 index 000000000000..3da9e81031d2 --- /dev/null +++ b/drivers/base/earlydev.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Texas Instruments + * Author: Bartosz Golaszewski + */ + +#include +#include + +#include "base.h" + +static bool early_done; +static LIST_HEAD(early_drvs); +static LIST_HEAD(early_devs); + +static void earlydev_pdev_set_name(struct platform_device *pdev) +{ + if (pdev->dev.init_name) + return; + + if (!slab_is_available()) { + pr_warn("slab unavailable - not assigning name to early device\n"); + return; + } + + switch (pdev->id) { + case PLATFORM_DEVID_NONE: + pdev->dev.init_name = kasprintf(GFP_KERNEL, "%s", pdev->name); + break; + case PLATFORM_DEVID_AUTO: + pr_warn("auto device ID not supported in early devices\n"); + break; + default: + pdev->dev.init_name = kasprintf(GFP_KERNEL, "%s.%d", + pdev->name, pdev->id); + break; + } + + if (!pdev->dev.init_name) + pr_warn("error allocating the early device name\n"); +} + +static void earlydev_probe_devices(void) +{ + struct earlydev_driver *edrv, *ndrv; + struct earlydev_device *edev, *ndev; + int rv; + + list_for_each_entry_safe(edev, ndev, &early_devs, list) { + if (edev->bound_to) + continue; + + list_for_each_entry_safe(edrv, ndrv, &early_drvs, list) { + if (strcmp(edrv->plat_drv.driver.name, + edev->pdev.name) != 0) + continue; + + earlydev_pdev_set_name(&edev->pdev); + rv = edrv->plat_drv.probe(&edev->pdev); + if (rv) { + if (rv == -EPROBE_DEFER) { + /* + * Move the device to the end of the + * list so that it'll be reprobed next + * time after all new devices. + */ + list_move_tail(&edev->list, + &early_devs); + continue; + } + + pr_err("error probing early device: %d\n", rv); + continue; + } + + edev->bound_to = edrv; + edev->pdev.early_probed = true; + } + } +} + +bool earlydev_probing_early(void) +{ + return !early_done; +} + +bool earlydev_probe_late(struct platform_device *pdev) +{ + struct earlydev_device *edev; + + edev = container_of(pdev, struct earlydev_device, pdev); + + return edev->probe_late; +} + +void __earlydev_driver_register(struct earlydev_driver *edrv, + struct module *owner) +{ + if (early_done) { + __platform_driver_register(&edrv->plat_drv, owner); + return; + } + + pr_debug("registering early driver: %s\n", edrv->plat_drv.driver.name); + + edrv->plat_drv.driver.owner = owner; + + INIT_LIST_HEAD(&edrv->list); + list_add(&early_drvs, &edrv->list); + + earlydev_probe_devices(); +} +EXPORT_SYMBOL_GPL(__earlydev_driver_register); + +void earlydev_device_add(struct earlydev_device *edev) +{ + if (early_done) { + platform_device_register(&edev->pdev); + return; + } + + pr_debug("adding early device: %s\n", edev->pdev.name); + + INIT_LIST_HEAD(&edev->list); + list_add(&early_devs, &edev->list); + + earlydev_probe_devices(); +} +EXPORT_SYMBOL_GPL(earlydev_device_add); + +static void earlydev_drivers_to_platform(void) +{ + struct earlydev_driver *edrv, *n; + struct platform_driver *pdrv; + int rv; + + list_for_each_entry_safe(edrv, n, &early_drvs, list) { + pdrv = &edrv->plat_drv; + + rv = __platform_driver_register(pdrv, pdrv->driver.owner); + if (rv) + pr_err("error switching early to platform driver: %d\n", + rv); + + list_del(&edrv->list); + } +} + +static void earlydev_devices_to_platform(void) +{ + struct earlydev_device *edev, *n; + struct platform_device *pdev; + int rv; + + list_for_each_entry_safe(edev, n, &early_devs, list) { + pdev = &edev->pdev; + + rv = platform_device_register(pdev); + if (rv) + pr_err("error switching early to platform device: %d\n", + rv); + } +} + +static int earlydev_switch_to_platform(void) +{ + pr_debug("switching early drivers and devices to platform\n"); + early_done = true; + + earlydev_drivers_to_platform(); + earlydev_devices_to_platform(); + + return 0; +} +device_initcall(earlydev_switch_to_platform); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 8075ddc70a17..fb51ce242f6c 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -574,7 +575,17 @@ static int platform_drv_probe(struct device *_dev) ret = dev_pm_domain_attach(_dev, true); if (ret != -EPROBE_DEFER) { if (drv->probe) { +#ifdef CONFIG_EARLYDEV + if (dev->early_probed && !earlydev_probe_late(dev)) { + /* Skip this probe if probed early. */ + dev->early_probed = false; + ret = 0; + } else { + ret = drv->probe(dev); + } +#else /* CONFIG_EARLYDEV */ ret = drv->probe(dev); +#endif /* CONFIG_EARLYDEV */ if (ret) dev_pm_domain_detach(_dev, true); } else { diff --git a/include/linux/earlydev.h b/include/linux/earlydev.h new file mode 100644 index 000000000000..7f190a904405 --- /dev/null +++ b/include/linux/earlydev.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 Texast Instruments + * Author: Bartosz Golaszewski + */ + +#ifndef __EARLYDEV_H__ +#define __EARLYDEV_H__ + +#include +#include +#include +#include + +struct earlydev_driver { + struct list_head list; + struct platform_driver plat_drv; +}; + +struct earlydev_device { + struct list_head list; + struct platform_device pdev; + struct earlydev_driver *bound_to; + bool probe_late; +}; + +#ifdef CONFIG_EARLYDEV +extern bool earlydev_probing_early(void); +extern bool earlydev_probe_late(struct platform_device *pdev); +extern void __earlydev_driver_register(struct earlydev_driver *edrv, + struct module *owner); +#define earlydev_driver_register(_driver) \ + __earlydev_driver_register((_driver), THIS_MODULE) +extern void earlydev_device_add(struct earlydev_device *edev); +#else /* CONFIG_EARLYDEV */ +static inline void earlydev_probing_early(void) +{ + return false; +} +static inline bool earlydev_probe_late(struct platform_device *pdev) +{ + return true; +} +static inline void __earlydev_driver_register(struct earlydev_driver *drv, + struct module *owner) {} +#define earlydev_driver_register(_driver) +static inline void earlydev_device_add(struct earlydev_device *edev) {} +#endif /* CONFIG_EARLYDEV */ + +/* + * REVISIT: early_initcall may be still too late for some timers and critical + * clocks. We should probably have a separate section with callbacks that can + * be invoked at each architecture's discretion. + */ +#define earlydev_platform_driver(_drv) \ + static int _drv##_register(void) \ + { \ + earlydev_driver_register(&(_drv)); \ + return 0; \ + } \ + early_initcall(_drv##_register) + +#endif /* __EARLYDEV_H__ */ diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 49f634d96118..5246f60f9aae 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -36,6 +36,10 @@ struct platform_device { /* arch specific additions */ struct pdev_archdata archdata; + +#ifdef CONFIG_EARLYDEV + bool early_probed; +#endif }; #define platform_get_device_id(pdev) ((pdev)->id_entry)