Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp4778251ybi; Mon, 3 Jun 2019 17:35:58 -0700 (PDT) X-Google-Smtp-Source: APXvYqx8NokrKgxbK5r3SABL8K0+WNUWvDVMNWQVtSUPkAIlr1LxCFVpNikysjaIjJVAd+DCyLdf X-Received: by 2002:a17:902:a98b:: with SMTP id bh11mr7654211plb.8.1559608558718; Mon, 03 Jun 2019 17:35:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559608558; cv=none; d=google.com; s=arc-20160816; b=euEk6yK7amEnRKwnrwHVKDa3vZkGWK/bPZvCudQ0U870Tam9SJ+tpyfESTlPFft+Ss k86Y1XLi6Pv4iU2kYthyGVGsjHGQ/Jf2yECA8AAu5quHWEk5qWhlYxlFwCD/jXJGQ0vQ iR1IbtFCSw7uCsaKsNNBoigDoE0951ye9Y6M9KTDLy/qmiDGZW1Swimu/YOLXp9ZouIB eP1A245HMXKDl+jphM/4YyOdrNv8QPOPgQbMPwy+Mekc2bAwF1uZ77AXM9CfbHDooRjR GDNueGDDpxtmRT1WMt1dfRTLaS3BtFSkPIV4U5+UKyEvOdQyzw6eR1Ea1Dqswv0wZsZQ YqnQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:dkim-signature; bh=iYnVK2VD7dXgk219JDN+y0uuA5LmcWu2ozSqT/x3Gx0=; b=ALlmVwRKNWKOK700DMjvkSNJQYF9INRPpAnRryinlWNVyR16od6I/dMa/Cx12gpQDX ImerZ9JwV96vigBYonoWapM77OLOfroMhTMUWLkTWey9vpuMihkvNWtHV7fNZvGp/VSR apmMjsTQNEbs9b/EkgTBfmkFeUXssLzkgaiCuAdvJ8jHsXBujohxNvh803Lh4LCaHSLe p/GO3YY8QWD1rQtE+wTpsmnqcuT0s60UMIMzNorBW5PkGzaj447UMlYQCYMGi+PtqzvW Q6cojvn4VJpOVsISzxm/rKQwTPINTtjt2PWGPUwZwbWeig/dq2vc44YaHld+L7mIA7uz wIJg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=bpGsT2ak; 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; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id x5si19532569pjv.62.2019.06.03.17.35.42; Mon, 03 Jun 2019 17:35:58 -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=@google.com header.s=20161025 header.b=bpGsT2ak; 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; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726728AbfFDAcm (ORCPT + 99 others); Mon, 3 Jun 2019 20:32:42 -0400 Received: from mail-qt1-f202.google.com ([209.85.160.202]:35158 "EHLO mail-qt1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726690AbfFDAcl (ORCPT ); Mon, 3 Jun 2019 20:32:41 -0400 Received: by mail-qt1-f202.google.com with SMTP id v58so9193722qta.2 for ; Mon, 03 Jun 2019 17:32:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=iYnVK2VD7dXgk219JDN+y0uuA5LmcWu2ozSqT/x3Gx0=; b=bpGsT2akWVHQnM/wcReSDOyezDgtpiilE9riCoi0RNCNb7TweMcXXiv/IOZFth3u6v U6B+ZBPJMMBmV5BsZkRoB7/bd0y9c5k1oQmJscH4658l5JUzwvQabt9bUA03opxDwCAR clSCW/jlH4Vspo/9g2O+RVbL0y+m/LTsQlIYSNLdRz3ecxOK80+eBQ4NLdpeNaEkV1tG EZtDBTbsQhqfpb2PuGq6Ch/6F7G9HmYawxrlNfhhV6qUseB/y/P3uZqewE1URdOANbxX uyTHRSzsGfIfxI7o3IT+O7qSb7ZOhPIVGbLzcLxt8+jFyoLSgjz/isi4K0yLEpM6LbS2 yOnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=iYnVK2VD7dXgk219JDN+y0uuA5LmcWu2ozSqT/x3Gx0=; b=mBrr0dTGRsZaWl+YYg84NPgQsaR9pDOpl3J2GRDd/1jzl7HzH5cPYR20Zd8+jnt/5I 8QDLKQjM7LHZubEhVNP7XShu8iOmCs4v0ENMiKbKoxrxgVqUzk0Kdpz/1oe2Xhdv30Zw fUM5BjLliqRL9dBJ+GDnYwjAeBz1UR/ndDYv/3ipoE5AXx73eCUpq8icFGTf0BbVGGvL ykqTBy3QnasnARGr6+WNYQExX5jav1szxowYoxewFcn/JstFQKDJhZXYZd9ChCPSWptt NQBt2FuypfdgNEP9wx0JJROClTMgiKcTRhbu99T8/rH/P47RCrv0gRNquXdPmNVQQrub U97A== X-Gm-Message-State: APjAAAVcHawSP+ffVfIJ1nn/NJNYyACWeAUehlrgn2fwSFUCbVC9ayT7 kTN0lLyMc57YLeENdGjs5ZD2z/T2R5Wk3C4= X-Received: by 2002:a37:7bc3:: with SMTP id w186mr24558996qkc.225.1559608359308; Mon, 03 Jun 2019 17:32:39 -0700 (PDT) Date: Mon, 3 Jun 2019 17:32:18 -0700 In-Reply-To: <20190604003218.241354-1-saravanak@google.com> Message-Id: <20190604003218.241354-6-saravanak@google.com> Mime-Version: 1.0 References: <20190604003218.241354-1-saravanak@google.com> X-Mailer: git-send-email 2.22.0.rc1.311.g5d7573a151-goog Subject: [RESEND PATCH v1 5/5] driver core: Add sync_state driver/bus callback From: Saravana Kannan To: Rob Herring , Mark Rutland , Greg Kroah-Hartman , "Rafael J. Wysocki" , Frank Rowand Cc: Saravana Kannan , David Collins , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This sync_state driver/bus callback is called once all the consumers of a supplier have probed successfully. This allows the supplier device's driver/bus to sync the supplier device's state to the software state with the guarantee that all the consumers are actively managing the resources provided by the supplier device. To maintain backwards compatibility and ease transition from existing frameworks and resource cleanup schemes, late_initcall_sync is the earliest when the sync_state callback might be called. There is no upper bound on the time by which the sync_state callback has to be called. This is because if a consumer device never probes, the supplier has to maintain its resources in the state left by the bootloader. For example, if the bootloader leaves the display backlight at a fixed voltage and the backlight driver is never probed, you don't want the backlight to ever be turned off after boot up. Signed-off-by: Saravana Kannan --- drivers/base/core.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/of/platform.c | 9 +++++++++ include/linux/device.h | 19 +++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index 9ab6782dda1c..7a8777a33e8c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -46,6 +46,7 @@ early_param("sysfs.deprecated", sysfs_deprecated_setup); /* Device links support. */ static LIST_HEAD(wait_for_suppliers); static DEFINE_MUTEX(wfs_lock); +static bool supplier_sync_state_enabled; #ifdef CONFIG_SRCU static DEFINE_MUTEX(device_links_lock); @@ -616,6 +617,41 @@ int device_links_check_suppliers(struct device *dev) return ret; } +static void __device_links_supplier_sync_state(struct device *dev) +{ + struct device_link *link; + + if (dev->state_synced) + return; + + list_for_each_entry(link, &dev->links.consumers, s_node) { + if (link->flags & DL_FLAG_STATELESS) + continue; + if (link->status != DL_STATE_ACTIVE) + return; + } + + if (dev->bus->sync_state) + dev->bus->sync_state(dev); + else if (dev->driver && dev->driver->sync_state) + dev->driver->sync_state(dev); + + dev->state_synced = true; +} + +int device_links_supplier_sync_state(struct device *dev, void *data) +{ + device_links_write_lock(); + __device_links_supplier_sync_state(dev); + device_links_write_unlock(); + return 0; +} + +void device_links_supplier_sync_state_enable(void) +{ + supplier_sync_state_enabled = true; +} + /** * device_links_driver_bound - Update device links after probing its driver. * @dev: Device to update the links for. @@ -660,6 +696,9 @@ void device_links_driver_bound(struct device *dev) WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); WRITE_ONCE(link->status, DL_STATE_ACTIVE); + + if (supplier_sync_state_enabled) + __device_links_supplier_sync_state(link->supplier); } dev->links.status = DL_DEV_DRIVER_BOUND; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index da1aa52b310a..b5cce0c2496a 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -604,6 +604,15 @@ static int __init of_platform_default_populate_init(void) return 0; } arch_initcall_sync(of_platform_default_populate_init); + +static int __init of_platform_sync_state_init(void) +{ + device_links_supplier_sync_state_enable(); + bus_for_each_dev(&platform_bus_type, NULL, NULL, + device_links_supplier_sync_state); + return 0; +} +late_initcall_sync(of_platform_sync_state_init); #endif int of_platform_device_destroy(struct device *dev, void *data) diff --git a/include/linux/device.h b/include/linux/device.h index 4e71e5386aae..f6d5bba098df 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -79,6 +79,13 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *); * that generate uevents to add the environment variables. * @probe: Called when a new device or driver add to this bus, and callback * the specific driver's probe to initial the matched device. + * @sync_state: Called to sync device state to software state after all the + * state tracking consumers linked to this device (present at + * the time of late_initcall) have successfully bound to a + * driver. If the device has no consumers, this function will + * be called at late_initcall_sync level. If the device has + * consumers that are never bound to a driver, this function + * will never get called until they do. * @remove: Called when a device removed from this bus. * @shutdown: Called at shut-down time to quiesce the device. * @@ -122,6 +129,7 @@ struct bus_type { int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); + void (*sync_state)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); @@ -251,6 +259,13 @@ enum probe_type { * @probe: Called to query the existence of a specific device, * whether this driver can work with it, and bind the driver * to a specific device. + * @sync_state: Called to sync device state to software state after all the + * state tracking consumers linked to this device (present at + * the time of late_initcall) have successfully bound to a + * driver. If the device has no consumers, this function will + * be called at late_initcall_sync level. If the device has + * consumers that are never bound to a driver, this function + * will never get called until they do. * @remove: Called when the device is removed from the system to * unbind a device from this driver. * @shutdown: Called at shut-down time to quiesce the device. @@ -288,6 +303,7 @@ struct device_driver { const struct acpi_device_id *acpi_match_table; int (*probe) (struct device *dev); + void (*sync_state)(struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); @@ -1058,6 +1074,7 @@ struct device { bool offline_disabled:1; bool offline:1; bool of_node_reused:1; + bool state_synced:1; #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) @@ -1400,6 +1417,8 @@ void device_link_remove(void *consumer, struct device *supplier); void device_link_wait_for_supplier(struct device *consumer); void device_link_check_waiting_consumers( int (*add_suppliers)(struct device *consumer)); +int device_links_supplier_sync_state(struct device *dev, void *data); +void device_links_supplier_sync_state_enable(void); #ifndef dev_fmt #define dev_fmt(fmt) fmt -- 2.22.0.rc1.257.g3120a18244-goog