From patchwork Tue Aug 1 09:23:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 109120 Delivered-To: patch@linaro.org Received: by 10.140.101.6 with SMTP id t6csp1267031qge; Tue, 1 Aug 2017 02:28:58 -0700 (PDT) X-Received: by 10.84.131.163 with SMTP id d32mr20009391pld.16.1501579738343; Tue, 01 Aug 2017 02:28:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1501579738; cv=none; d=google.com; s=arc-20160816; b=q80rTQ5AeUnfChNlBaoumqYs15yAWodDPQ93UB9pOCGYZyOYaHuBiCb7Kdm6+EXxL6 ayPa21rQ3fQIm3oiyib06ea7qSuLkzxRGzmoWJ4+DiaKgH5Ht058QyzPDBOs/JX6iVxE hebRqwj4rzvwH7QascY8q9SDgEhboK3KEKlO7uDnEiCcQrPeZyepYtsDrulmmgKtLoVv a2LHE4nf1gKafO6quWB2oIUwAYr58AK99L7dceXKcysICZM5qfv9gwYcbGD1UktV9J2m irOvbDCl8N8dPT0gcCpXUm0gyHS5V2ANU0XrSBFppu4C1qReHgt/dt8IVS/1XAV29h0j waWA== 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=Bn3eKKtJ+ja/c3q4C2aIQGvbuWmnJRzIILYqL7H80c0=; b=kj1+WBacuYRjwfa37b4EJwO7HJ/YKR5+/rS7Pw7467UHNcGbHXleqRBZX1W73KTSrr M53cJheK4uFbd/7nzuxNJi/VyXAs4/u4Uhq8puwrjzSC/DsH5lbyk3ZQssI09W247/4s LIN2+eiIl90ToQPLd3PG3N2VCk0ae2C6GczNuvUGuJ1NMWynK8TtpUyxr45tXVdf7Lm5 uig2oJPOmQxI0FOx12JflYkZWSFVqR/87cMPESlymPncb21KGGrrcsF/ksm9QgrzIU2s AR1iB06B6i/TYfzPUsHXaP3l86OXdF3UNQB7nuVtdraNQ3QDy10UIwgEv9ElEqcl+hHj 0nBg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.b=Pmb0q9x5; 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 32si16891423plb.992.2017.08.01.02.28.58; Tue, 01 Aug 2017 02:28: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=@linaro.org header.b=Pmb0q9x5; 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 S1751802AbdHAJ2z (ORCPT + 26 others); Tue, 1 Aug 2017 05:28:55 -0400 Received: from mail-pf0-f180.google.com ([209.85.192.180]:33888 "EHLO mail-pf0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751623AbdHAJ2v (ORCPT ); Tue, 1 Aug 2017 05:28:51 -0400 Received: by mail-pf0-f180.google.com with SMTP id o86so2173084pfj.1 for ; Tue, 01 Aug 2017 02:28:51 -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=Bn3eKKtJ+ja/c3q4C2aIQGvbuWmnJRzIILYqL7H80c0=; b=Pmb0q9x5zhskMUQ35sCoWgfKENytco8QiJvnudPFoxKdUcntFxzvFkFArtVOXI4zd2 sUYO26FskUN4x1CyuJY4dtxZu/7kQBLfgIoYMf0mEuUXNHWgf398ot9IFuFApB/O/sCX HFY9cmp/J6TU7k3qa3m0M4ksdIEGsbJdHEguU= 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=Bn3eKKtJ+ja/c3q4C2aIQGvbuWmnJRzIILYqL7H80c0=; b=Gxzfwub9JLnd45gi5efEOvpFbO5yXfGr9R9P0bZ/q3WEzgPuzpSgwj7/FkRu/RpmGK Er9CVUI5/T355sjs21uTNkLFAL4Idw1HJhlBmaFvblxQYaxD4fEs7zTUpULNcie9WB1l rak5wSAp5Slc3z3QAUwOfI4jG4lzlbp10o1wcL6qyV4rU1z5uEwLZ3wE1UmTqlAZQ03Y gBirDFWi6bQmPBpDJN6G4yICwSoTNs6YCtyCg53KZHTRN6KgpMjwNHaRfEMzUZTqLv14 ssby5hq364rkEG+4+DhXtSAWT+RaoVsc7rYW9dIps+OszbD/3+3crmX6VMn2qQYwMcfO cQWA== X-Gm-Message-State: AIVw112gYhbX4EzIuGA6ex6mahtGxLBMHbQvBaru+JGb5+jNdXDNKPp3 /OOToc7U6kKfqM0v X-Received: by 10.84.236.4 with SMTP id q4mr20204023plk.423.1501579730788; Tue, 01 Aug 2017 02:28:50 -0700 (PDT) Received: from localhost ([122.172.27.66]) by smtp.gmail.com with ESMTPSA id p126sm48021509pfp.28.2017.08.01.02.28.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 01 Aug 2017 02:28:49 -0700 (PDT) From: Viresh Kumar To: Greg Kroah-Hartman Cc: Viresh Kumar , Vincent Guittot , Mark Brown , Stephen Boyd , Rajendra Nayak , Shiraz Hashim , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, robdclark@gmail.com Subject: [PATCH V3 1/8] drivers: Add boot constraints core Date: Tue, 1 Aug 2017 14:53:42 +0530 Message-Id: <1a844e27ee7e0b22acf8ea582bf4e8d35f54c84a.1501578037.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.13.0.71.gd7076ec9c9cb 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 Some devices are powered ON by the bootloader before the bootloader handovers control to Linux. It maybe important for those devices to keep working until the time a Linux device driver probes the device and reconfigure its resources. A typical example of that can be the LCD controller, which is used by the bootloaders to show image(s) while the platform is booting into Linux. The LCD controller can be using some resources, like clk, regulators, PM domain, etc, that are shared between several devices. These shared resources should be configured to satisfy need of all the users. If another device's (X) driver gets probed before the LCD controller driver in this case, then it may end up reconfiguring these resources to ranges satisfying the current users (only device X) and that can make the LCD screen unstable. This patch introduces the concept of boot-constraints, which will be set by the bootloaders and the kernel will satisfy them until the time driver for such a device is probed (successfully or unsuccessfully). The list of boot constraint types is empty for now, and will be incrementally updated by later patches. Only two routines are exposed by the boot constraints core for now: - dev_boot_constraint_add(): This shall be called by parts of the kernel (before the device is probed) to set the constraints. - dev_boot_constraints_remove(): This is called only by the driver core after a device is probed successfully or unsuccessfully. Special handling is done here for deffered probing. Tested-by: Rajendra Nayak Signed-off-by: Viresh Kumar --- drivers/base/Kconfig | 10 ++ drivers/base/Makefile | 1 + drivers/base/boot_constraints/Makefile | 3 + drivers/base/boot_constraints/core.c | 199 +++++++++++++++++++++++++++++++++ drivers/base/boot_constraints/core.h | 33 ++++++ drivers/base/dd.c | 20 ++-- include/linux/boot_constraint.h | 46 ++++++++ 7 files changed, 305 insertions(+), 7 deletions(-) create mode 100644 drivers/base/boot_constraints/Makefile create mode 100644 drivers/base/boot_constraints/core.c create mode 100644 drivers/base/boot_constraints/core.h create mode 100644 include/linux/boot_constraint.h -- 2.13.0.71.gd7076ec9c9cb diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index f046d21de57d..2333db2a33b7 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -347,4 +347,14 @@ config GENERIC_ARCH_TOPOLOGY appropriate scaling, sysfs interface for changing capacity values at runtime. +config DEV_BOOT_CONSTRAINTS + bool "Boot constraints for devices" + help + This enables boot constraints detection for devices. These constraints + are (normally) set by the Bootloader and must be satisfied by the + kernel until the relevant device driver is probed. Once the driver is + probed, the constraint is dropped. + + If unsure, say N. + endmenu diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 397e5c344e6a..8c37ca07114b 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -5,6 +5,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ cpu.o firmware.o init.o map.o devres.o \ attribute_container.o transport_class.o \ topology.o container.o property.o cacheinfo.o +obj-$(CONFIG_DEV_BOOT_CONSTRAINTS) += boot_constraints/ obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-$(CONFIG_DMA_CMA) += dma-contiguous.o obj-y += power/ diff --git a/drivers/base/boot_constraints/Makefile b/drivers/base/boot_constraints/Makefile new file mode 100644 index 000000000000..0f2680177974 --- /dev/null +++ b/drivers/base/boot_constraints/Makefile @@ -0,0 +1,3 @@ +# Makefile for device boot constraints + +obj-y := core.o diff --git a/drivers/base/boot_constraints/core.c b/drivers/base/boot_constraints/core.c new file mode 100644 index 000000000000..366a05d6d9ba --- /dev/null +++ b/drivers/base/boot_constraints/core.c @@ -0,0 +1,199 @@ +/* + * This takes care of boot time device constraints, normally set by the + * Bootloader. + * + * 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 "core.h" + +#define for_each_constraint(_constraint, _temp, _cdev) \ + list_for_each_entry_safe(_constraint, _temp, &_cdev->constraints, node) + +/* Global list of all constraint devices currently registered */ +static LIST_HEAD(constraint_devices); +static DEFINE_MUTEX(constraint_devices_mutex); + +/* Boot constraints core */ + +static struct constraint_dev *constraint_device_find(struct device *dev) +{ + struct constraint_dev *cdev; + + list_for_each_entry(cdev, &constraint_devices, node) { + if (cdev->dev == dev) + return cdev; + } + + return NULL; +} + +static struct constraint_dev *constraint_device_allocate(struct device *dev) +{ + struct constraint_dev *cdev; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return ERR_PTR(-ENOMEM); + + cdev->dev = dev; + INIT_LIST_HEAD(&cdev->node); + INIT_LIST_HEAD(&cdev->constraints); + + list_add(&cdev->node, &constraint_devices); + + return cdev; +} + +static void constraint_device_free(struct constraint_dev *cdev) +{ + list_del(&cdev->node); + kfree(cdev); +} + +static struct constraint_dev *constraint_device_get(struct device *dev) +{ + struct constraint_dev *cdev; + + cdev = constraint_device_find(dev); + if (cdev) + return cdev; + + cdev = constraint_device_allocate(dev); + if (IS_ERR(cdev)) { + dev_err(dev, "Failed to add constraint dev (%ld)\n", + PTR_ERR(cdev)); + } + + return cdev; +} + +static void constraint_device_put(struct constraint_dev *cdev) +{ + if (!list_empty(&cdev->constraints)) + return; + + constraint_device_free(cdev); +} + +static struct constraint *constraint_allocate(struct constraint_dev *cdev, + enum dev_boot_constraint_type type) +{ + struct constraint *constraint; + int (*add)(struct constraint *constraint, void *data); + void (*remove)(struct constraint *constraint); + + switch (type) { + default: + return ERR_PTR(-EINVAL); + } + + constraint = kzalloc(sizeof(*constraint), GFP_KERNEL); + if (!constraint) + return ERR_PTR(-ENOMEM); + + constraint->cdev = cdev; + constraint->type = type; + constraint->add = add; + constraint->remove = remove; + INIT_LIST_HEAD(&constraint->node); + + list_add(&constraint->node, &cdev->constraints); + + return constraint; +} + +static void constraint_free(struct constraint *constraint) +{ + list_del(&constraint->node); + kfree(constraint); +} + +int dev_boot_constraint_add(struct device *dev, + struct dev_boot_constraint_info *info) +{ + struct constraint_dev *cdev; + struct constraint *constraint; + int ret; + + mutex_lock(&constraint_devices_mutex); + + /* Find or add the cdev type first */ + cdev = constraint_device_get(dev); + if (IS_ERR(cdev)) { + ret = PTR_ERR(cdev); + goto unlock; + } + + constraint = constraint_allocate(cdev, info->constraint.type); + if (IS_ERR(constraint)) { + dev_err(dev, "Failed to add constraint type: %d (%ld)\n", + info->constraint.type, PTR_ERR(constraint)); + ret = PTR_ERR(constraint); + goto put_cdev; + } + + constraint->free_resources = info->free_resources; + constraint->free_resources_data = info->free_resources_data; + + /* Set constraint */ + ret = constraint->add(constraint, info->constraint.data); + if (ret) + goto free_constraint; + + dev_dbg(dev, "Added boot constraint-type (%d)\n", + info->constraint.type); + + mutex_unlock(&constraint_devices_mutex); + + return 0; + +free_constraint: + constraint_free(constraint); +put_cdev: + constraint_device_put(cdev); +unlock: + mutex_unlock(&constraint_devices_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_boot_constraint_add); + +static void constraint_remove(struct constraint *constraint) +{ + constraint->remove(constraint); + + if (constraint->free_resources) + constraint->free_resources(constraint->free_resources_data); + + constraint_free(constraint); +} + +void dev_boot_constraints_remove(struct device *dev) +{ + struct constraint_dev *cdev; + struct constraint *constraint, *temp; + + mutex_lock(&constraint_devices_mutex); + + cdev = constraint_device_find(dev); + if (!cdev) + goto unlock; + + for_each_constraint(constraint, temp, cdev) + constraint_remove(constraint); + + constraint_device_put(cdev); +unlock: + mutex_unlock(&constraint_devices_mutex); +} diff --git a/drivers/base/boot_constraints/core.h b/drivers/base/boot_constraints/core.h new file mode 100644 index 000000000000..7ba4ac172c09 --- /dev/null +++ b/drivers/base/boot_constraints/core.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 Linaro. + * Viresh Kumar + * + * This file is released under the GPLv2. + */ +#ifndef _CORE_H +#define _CORE_H + +#include +#include +#include + +struct constraint_dev { + struct device *dev; + struct list_head node; + struct list_head constraints; +}; + +struct constraint { + struct constraint_dev *cdev; + struct list_head node; + enum dev_boot_constraint_type type; + void (*free_resources)(void *data); + void *free_resources_data; + + int (*add)(struct constraint *constraint, void *data); + void (*remove)(struct constraint *constraint); + void *private; +}; + +/* Forward declarations of constraint specific callbacks */ +#endif /* _CORE_H */ diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c17fefc77345..2262a4a4c0e4 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -17,6 +17,7 @@ * This file is released under the GPLv2 */ +#include #include #include #include @@ -383,15 +384,20 @@ static int really_probe(struct device *dev, struct device_driver *drv) */ devices_kset_move_last(dev); - if (dev->bus->probe) { + if (dev->bus->probe) ret = dev->bus->probe(dev); - if (ret) - goto probe_failed; - } else if (drv->probe) { + else if (drv->probe) ret = drv->probe(dev); - if (ret) - goto probe_failed; - } + + /* + * Remove boot constraints for both successful and unsuccessful probe(), + * except for the case where EPROBE_DEFER is returned by probe(). + */ + if (ret != -EPROBE_DEFER) + dev_boot_constraints_remove(dev); + + if (ret) + goto probe_failed; if (test_remove) { test_remove = false; diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h new file mode 100644 index 000000000000..ae34fee547c5 --- /dev/null +++ b/include/linux/boot_constraint.h @@ -0,0 +1,46 @@ +/* + * Boot constraints header. + * + * Copyright (C) 2017 Linaro. + * Viresh Kumar + * + * This file is released under the GPLv2 + */ +#ifndef _LINUX_BOOT_CONSTRAINT_H +#define _LINUX_BOOT_CONSTRAINT_H + +#include +#include + +struct device; + +enum dev_boot_constraint_type { + DEV_BOOT_CONSTRAINT_NONE, +}; + +struct dev_boot_constraint { + enum dev_boot_constraint_type type; + void *data; +}; + +struct dev_boot_constraint_info { + struct dev_boot_constraint constraint; + + /* This will be called just before the constraint is removed */ + void (*free_resources)(void *data); + void *free_resources_data; +}; + +#ifdef CONFIG_DEV_BOOT_CONSTRAINTS +int dev_boot_constraint_add(struct device *dev, + struct dev_boot_constraint_info *info); +void dev_boot_constraints_remove(struct device *dev); +#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) {} +#endif /* CONFIG_DEV_BOOT_CONSTRAINTS */ + +#endif /* _LINUX_BOOT_CONSTRAINT_H */