Received: by 10.192.165.148 with SMTP id m20csp2281536imm; Thu, 26 Apr 2018 08:31:13 -0700 (PDT) X-Google-Smtp-Source: AIpwx49AYJnhDr8znbtUoFf+bI1VLND0uw1uBG7uUM0fVE6GnN7Ywcw8VVYXntZOsH4mRYkAy0ls X-Received: by 2002:a17:902:5ac1:: with SMTP id g1-v6mr22036305plm.43.1524756673216; Thu, 26 Apr 2018 08:31:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524756673; cv=none; d=google.com; s=arc-20160816; b=jccG0ZeydLlQeXa/+CSu0gJtfbXHrnVL/U92WtJP6PspRIjjKKi3bOCh4G+hAT1z1V w2jzsuM8NyGrJucvB1iCOh83oBWLImFgF5O0vKKcncfQH63TrvRb3l1RWk6p0TQNTev2 YZ/41zbhxDGa0Z0NnQki4wO+eQOMUDf9oePMTuX40bPSQ8mJQ7c2Ywl0WeRKC1/zWKNH ZmhhjQ23Av0umHbmKWrorhvSpqWDhzjiGo0U2H33el0JeBkSDBmZ8rM0vaZ68CIOB2iC raRHFkUYq7hZzVRH8e6tTDp2rn6RXvOYOMlm0GCc5eKpr5DXDDsR7tPjT4YQw0l/tCBo Eyvg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=dP/iv4nYZ2Zzzb9UJyIQSqixu5+U0vTlmCuWP8NrWuU=; b=toFDJY8UobO4JywXy1slcfLd+TOMp7g6ZomxGqo8r4QNd3v5KyREnzacqOBFjjxUV+ 0M4BHG1oYfmfId/FoFFtbTlsl4cwREYdceFGgC9daOwYcXkH9xidWnb2/ydUGG1nwgQd pTbH6eiou3hEfr2P7WseL9E8YmHMKhayW7e2wROo8tYhbuiAwXD+5dCJpWDqfNGHEfYv rh4TxNrj/vRu9YagoygnOz+HL4i3GgWwURu5Xb2IetHmXcHpkQJitqsqhcqbh5g+cp44 khJBW1YCNc049HTUAiN9QZesHSwKtDcd31RzNMc1fb9MhdSqlUDKdFJDWycIOeE10qjG 0fLA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@bgdev-pl.20150623.gappssmtp.com header.s=20150623 header.b=A3JLp0eI; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f186si14588013pfg.191.2018.04.26.08.30.58; Thu, 26 Apr 2018 08:31:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@bgdev-pl.20150623.gappssmtp.com header.s=20150623 header.b=A3JLp0eI; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756414AbeDZP3u (ORCPT + 99 others); Thu, 26 Apr 2018 11:29:50 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:35957 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756627AbeDZP3i (ORCPT ); Thu, 26 Apr 2018 11:29:38 -0400 Received: by mail-wm0-f65.google.com with SMTP id n10so14027027wmc.1 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=KXJ4fHqPOI7SMxyllgjbErHMG7+RjLdCP7Pbb9p98aNxiPXdhsXGrdwEn5muy78XZY v4RRgIjAsNaVbmww37PwyszaKRDDfw1qB/IRQqedxeiRQCKybzvbMzsnY9tpWWLIHOxN A4tOmqxS471SlrssGVADuxNlAarUr0OpIeDmouGygS/fX1JOvFLXqcQCEAxsbDQFG2yo uPfbkUhRWoHCN0lWHB0EW2T3G2jHH1oZ1hV7sXAamv61Vs8tcRVDmb2rKnty3Rm3ldZv GeARLgcvtXDR0CJH/GxyFhMpHHnlstqousb44hojEqY57te8RgTGuJ3uPhtHs64S2RO9 SHXg== X-Gm-Message-State: ALQs6tDnCMrbQVp9EGbhD8oMH+UBY51u8ErXkn2d3mHHnE9rSXoa6oss DVkF8JN0YLT9M0pyPH84MV+veQ== 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 Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Bartosz Golaszewski 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> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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) -- 2.17.0