From patchwork Sun Oct 29 13:48:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 117409 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp1527489qgn; Sun, 29 Oct 2017 06:49:41 -0700 (PDT) X-Google-Smtp-Source: ABhQp+SFDepIngrvszt2m14krXA8H9RKF23jdAVy7jcOkkOSIg06A90ByRiC3rmtgD8u/Orx3kLW X-Received: by 10.99.127.78 with SMTP id p14mr5076523pgn.176.1509284981578; Sun, 29 Oct 2017 06:49:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1509284981; cv=none; d=google.com; s=arc-20160816; b=yRXTQw6m3FOxcuvpdcQ9W1OGRESkgwKROhIKsY2y7NGO8ParAGRcwW0dbzX6JeXLp7 /t5XpAcco12y1OGsVgVOWwuS+s84XlJ/SxQVR2Q53Wr2ypl/Lj5I6sFqoXMDJjGbGwlK wqhHrCxsLVWqqdx3bxLDzgZJ9QecjPMouC7iLwgfD4cyVbUE183tTTdShYjJJpYiClqK q6GCO6PuK2GNCQEDE66snMnLVoZFicwrlT907K0s3ma+ft5xjOzVaD/9bCaPKP6VVSAF H1miOsJbte3SgsKsoCb0ksna4YpZMroeP+lplLOYp1v5f8WyYsGDwvrgEH57FgbYUJtD SK7A== 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:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=HRWFFgoVipB7peY01mzoJOe1W3nY5LSo0Zht3Rq225s=; b=pqXbfIK8EWmq8Kuyua2Nz5h0btbDKa6ZHTATTJybuAVnztYNd0VhVS6Cf3SJOjtqYM THSGvbAwVCLrFiZwvacFUlSgyTPSY0N9UCWNSzIPi1+cyRultbApu2LRyCgUkU5ObTv7 w7KdhEqX2wJ7HQqvAXKk64Q4cd5cbMq+cjjS/+Cwani3AtD9LaxlSfqJWvGBQsK52OZr w563LeEJ/SjmTEbyqVGqHlCVcPlFgDj8YCoKu6CpGDhRZsGxzmmW4Gv7KpX4cg5fZKRY Go/3AEKqQBqZ5zJqOQquEqtnhYULyEnOqcWNyKRGAHOTfagAecQCVvbt4RtVX4rXCBS/ MlSg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=M0P3+8yg; 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=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j6si8653501pfh.329.2017.10.29.06.49.41; Sun, 29 Oct 2017 06:49:41 -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=@linaro.org header.s=google header.b=M0P3+8yg; 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=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751846AbdJ2Nti (ORCPT + 27 others); Sun, 29 Oct 2017 09:49:38 -0400 Received: from mail-pg0-f66.google.com ([74.125.83.66]:51122 "EHLO mail-pg0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751676AbdJ2Ntc (ORCPT ); Sun, 29 Oct 2017 09:49:32 -0400 Received: by mail-pg0-f66.google.com with SMTP id y5so9109842pgq.7 for ; Sun, 29 Oct 2017 06:49:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=HRWFFgoVipB7peY01mzoJOe1W3nY5LSo0Zht3Rq225s=; b=M0P3+8ygjJC30N1igxngPg44LVznhTdyHzbmiF2N0+pmaBXvo8AEuAPIFfOhCrqGoA R+OJKQPufJzLYLAcrfoSaN/meQYs7U2hdP4/WIAmA42b1goMBVdHZmA9E+V9YKr1AK6E r8UoBGCOhlBXXrqwCE0+uto3SpS3VZKDGUD8A= 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:in-reply-to:references; bh=HRWFFgoVipB7peY01mzoJOe1W3nY5LSo0Zht3Rq225s=; b=oWaPamr0OJI/aGqNWOuRUehqhhQ7vTcw+ZM5ObWqIIgHJJ8QoslG+js97DB/0tCYJh ev3F7Hfnw1fRmuIVwYupv4ZbQ2Bk654EynAydFHaDXvbb4a+rC86aUxw6mYXmDo/OAl2 UL1TGddxGljL/gSNAQw7CgrzlhaIMgdBU0XygSScq8vuCAmvDpYc+Vo4Z7UZHYt5/+ay 4g+FS6J1bG2C60p+AsWuMrc5gCXuviyo4zpJ4vC3+uZZoD8wwTQkilUBXArPHPtfoHBP 4gCapGHvPS5aR3c0m6JXIR1KZEdwSL54XBac4IOeDeuBptTExy7VR8ie19gt1axWpy0f 5eJw== X-Gm-Message-State: AMCzsaXGLlwQaDj/KKYsEtJfxp8LsZjZAhzD0svNrw3bwRYZWcI2WQHQ T7MQONrRrWbSJuHa6HO0f5PvvA== X-Received: by 10.98.53.1 with SMTP id c1mr6009273pfa.248.1509284971633; Sun, 29 Oct 2017 06:49:31 -0700 (PDT) Received: from localhost ([122.167.161.211]) by smtp.gmail.com with ESMTPSA id a70sm25782019pfg.176.2017.10.29.06.49.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 29 Oct 2017 06:49:31 -0700 (PDT) From: Viresh Kumar To: Greg Kroah-Hartman Cc: Viresh Kumar , Vincent Guittot , Stephen Boyd , Rajendra Nayak , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, robdclark@gmail.com, s.hauer@pengutronix.de, l.stach@pengutronix.de, shawnguo@kernel.org, fabio.estevam@nxp.com, nm@ti.com, xuwei5@hisilicon.com, robh+dt@kernel.org Subject: [PATCH V4 08/12] boot_constraint: Manage deferrable constraints Date: Sun, 29 Oct 2017 19:18:56 +0530 Message-Id: <88c7a0a6421d267c118f501ea1e920b04649002d.1509284255.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.15.0.rc1.236.g92ea95045093 In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org It is possible that some of the resources aren't available at the time constraints are getting set and the boot constraints core will return -EPROBE_DEFER for them. In order to retry adding the constraints at a later point of time (after the resource is added and before any of its users come up), this patch proposes two things: - Each constraint is represented by a virtual platform device, so that it is re-probed again until the time all the dependencies aren't met. The platform device is removed along with the constraint, with help of the free_resources() callback. - Enable early defer probing support by calling driver_enable_deferred_probe(), so that the core retries probing deferred devices every time any device is bound to a driver. This makes sure that the constraint is set before any of the users of the resources come up. This is tested on ARM64 Hikey board where probe was deferred for a device. Tested-by: Rajendra Nayak Signed-off-by: Viresh Kumar --- drivers/base/dd.c | 12 ++ drivers/boot_constraints/Makefile | 2 +- drivers/boot_constraints/deferrable_dev.c | 235 ++++++++++++++++++++++++++++++ include/linux/boot_constraint.h | 14 ++ 4 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 drivers/boot_constraints/deferrable_dev.c -- 2.15.0.rc1.236.g92ea95045093 diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 4eec27fe2b2b..19eff5d08b9a 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -228,6 +228,18 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +/** + * driver_enable_deferred_probe() - Enable probing of deferred devices + * + * We don't want to get in the way when the bulk of drivers are getting probed + * and so deferred probe is disabled in the beginning. Enable it now because we + * need it. + */ +void driver_enable_deferred_probe(void) +{ + driver_deferred_probe_enable = true; +} + /** * deferred_probe_initcall() - Enable probing of deferred devices * diff --git a/drivers/boot_constraints/Makefile b/drivers/boot_constraints/Makefile index b7ade1a7afb5..a765094623a3 100644 --- a/drivers/boot_constraints/Makefile +++ b/drivers/boot_constraints/Makefile @@ -1,3 +1,3 @@ # Makefile for device boot constraints -obj-y := clk.o core.o pm.o supply.o +obj-y := clk.o deferrable_dev.o core.o pm.o supply.o diff --git a/drivers/boot_constraints/deferrable_dev.c b/drivers/boot_constraints/deferrable_dev.c new file mode 100644 index 000000000000..04056f317aff --- /dev/null +++ b/drivers/boot_constraints/deferrable_dev.c @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2017 Linaro. + * Viresh Kumar + * + * This file is released under the GPLv2. + */ + +#define pr_fmt(fmt) "Boot Constraints: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" + +static DEFINE_IDA(pdev_index); + +void driver_enable_deferred_probe(void); + +struct boot_constraint_pdata { + struct device *dev; + struct dev_boot_constraint constraint; + int probe_failed; + int index; +}; + +static void boot_constraint_remove(void *data) +{ + struct platform_device *pdev = data; + struct boot_constraint_pdata *pdata = dev_get_platdata(&pdev->dev); + + ida_simple_remove(&pdev_index, pdata->index); + kfree(pdata->constraint.data); + platform_device_unregister(pdev); +} + +/* + * A platform device is added for each and every constraint, to handle + * -EPROBE_DEFER properly. + */ +static int boot_constraint_probe(struct platform_device *pdev) +{ + struct boot_constraint_pdata *pdata = dev_get_platdata(&pdev->dev); + struct dev_boot_constraint_info info; + int ret; + + if (WARN_ON(!pdata)) + return -EINVAL; + + info.constraint = pdata->constraint; + info.free_resources = boot_constraint_remove; + info.free_resources_data = pdev; + + ret = dev_boot_constraint_add(pdata->dev, &info); + if (ret) { + if (ret == -EPROBE_DEFER) + driver_enable_deferred_probe(); + else + pdata->probe_failed = ret; + } + + return ret; +} + +static struct platform_driver boot_constraint_driver = { + .driver = { + .name = "boot-constraints-dev", + }, + .probe = boot_constraint_probe, +}; + +static int __init boot_constraint_init(void) +{ + return platform_driver_register(&boot_constraint_driver); +} +core_initcall(boot_constraint_init); + +static int boot_constraint_add_dev(struct device *dev, + struct dev_boot_constraint *constraint) +{ + struct boot_constraint_pdata pdata = { + .dev = dev, + .constraint.type = constraint->type, + }; + struct platform_device *pdev; + struct boot_constraint_pdata *pdev_pdata; + int size, ret; + + switch (constraint->type) { + case DEV_BOOT_CONSTRAINT_CLK: + size = sizeof(struct dev_boot_constraint_clk_info); + break; + case DEV_BOOT_CONSTRAINT_PM: + size = 0; + break; + case DEV_BOOT_CONSTRAINT_SUPPLY: + size = sizeof(struct dev_boot_constraint_supply_info); + break; + default: + dev_err(dev, "%s: Constraint type (%d) not supported\n", + __func__, constraint->type); + return -EINVAL; + } + + /* Will be freed from boot_constraint_remove() */ + pdata.constraint.data = kmemdup(constraint->data, size, GFP_KERNEL); + if (!pdata.constraint.data) + return -ENOMEM; + + ret = ida_simple_get(&pdev_index, 0, 256, GFP_KERNEL); + if (ret < 0) { + dev_err(dev, "failed to allocate index (%d)\n", ret); + goto free; + } + + pdata.index = ret; + + pdev = platform_device_register_data(NULL, "boot-constraints-dev", ret, + &pdata, sizeof(pdata)); + if (IS_ERR(pdev)) { + dev_err(dev, "%s: Failed to create pdev (%ld)\n", __func__, + PTR_ERR(pdev)); + ret = PTR_ERR(pdev); + goto ida_remove; + } + + /* Release resources if probe has failed */ + pdev_pdata = dev_get_platdata(&pdev->dev); + if (pdev_pdata->probe_failed) { + ret = pdev_pdata->probe_failed; + goto remove_pdev; + } + + return 0; + +remove_pdev: + platform_device_unregister(pdev); +ida_remove: + ida_simple_remove(&pdev_index, pdata.index); +free: + kfree(pdata.constraint.data); + + return ret; +} + +static int dev_boot_constraint_add_deferrable(struct device *dev, + struct dev_boot_constraint *constraints, int count) +{ + int ret, i; + + for (i = 0; i < count; i++) { + ret = boot_constraint_add_dev(dev, &constraints[i]); + if (ret) + return ret; + } + + return 0; +} + +/* This only creates platform devices for now */ +static void add_deferrable_of_single(struct device_node *np, + struct dev_boot_constraint *constraints, + int count) +{ + struct device *dev; + int ret; + + if (!of_device_is_available(np)) + return; + + ret = of_platform_bus_create(np, NULL, NULL, NULL, false); + if (ret) + return; + + if (of_device_is_compatible(np, "arm,primecell")) { + struct amba_device *adev = of_find_amba_device_by_node(np); + + if (!adev) { + pr_err("Failed to find amba dev: %s\n", np->full_name); + return; + } + dev = &adev->dev; + } else { + struct platform_device *pdev = of_find_device_by_node(np); + + if (!pdev) { + pr_err("Failed to find pdev: %s\n", np->full_name); + return; + } + dev = &pdev->dev; + } + + ret = dev_boot_constraint_add_deferrable(dev, constraints, count); + if (ret) + dev_err(dev, "Failed to add boot constraint (%d)\n", ret); +} + +/* Not all compatible device nodes may have boot constraints */ +static bool node_has_boot_constraints(struct device_node *np, + struct dev_boot_constraint_of *oconst) +{ + int i; + + if (!oconst->dev_names) + return true; + + for (i = 0; i < oconst->dev_names_count; i++) { + if (!strcmp(oconst->dev_names[i], kbasename(np->full_name))) + return true; + } + + return false; +} + +void dev_boot_constraint_add_deferrable_of(struct dev_boot_constraint_of *oconst, + int count) +{ + struct device_node *np; + int i; + + for (i = 0; i < count; i++) { + for_each_compatible_node(np, NULL, oconst[i].compat) { + if (!node_has_boot_constraints(np, &oconst[i])) + continue; + + add_deferrable_of_single(np, oconst[i].constraints, + oconst[i].count); + } + } +} +EXPORT_SYMBOL_GPL(dev_boot_constraint_add_deferrable_of); diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h index 637fe9d65536..c110b36e490f 100644 --- a/include/linux/boot_constraint.h +++ b/include/linux/boot_constraint.h @@ -35,6 +35,15 @@ struct dev_boot_constraint { void *data; }; +struct dev_boot_constraint_of { + const char *compat; + struct dev_boot_constraint *constraints; + unsigned int count; + + const char **dev_names; + unsigned int dev_names_count; +}; + struct dev_boot_constraint_info { struct dev_boot_constraint constraint; @@ -47,12 +56,17 @@ struct dev_boot_constraint_info { int dev_boot_constraint_add(struct device *dev, struct dev_boot_constraint_info *info); void dev_boot_constraints_remove(struct device *dev); +void dev_boot_constraint_add_deferrable_of(struct dev_boot_constraint_of *oconst, + int count); #else static inline int dev_boot_constraint_add(struct device *dev, struct dev_boot_constraint_info *info) { return -EINVAL; } static inline void dev_boot_constraints_remove(struct device *dev) {} +void dev_boot_constraint_add_deferrable_of(struct dev_boot_constraint_of *oconst, + int count) +{ } #endif /* CONFIG_DEV_BOOT_CONSTRAINTS */ #endif /* _LINUX_BOOT_CONSTRAINT_H */