From patchwork Wed Jan 10 03:47:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 124009 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp4791142qgn; Tue, 9 Jan 2018 19:52:17 -0800 (PST) X-Google-Smtp-Source: ACJfBouoca1YMz/7gLXh6wJxjggtDy6WuJ2aCePhc8vfOa8Sc1KyfT1FPvjv1qRinglodKlRLHo/ X-Received: by 10.84.245.130 with SMTP id j2mr8840993pll.135.1515556337249; Tue, 09 Jan 2018 19:52:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1515556337; cv=none; d=google.com; s=arc-20160816; b=x5v20WKiRtEwzwA1M3gS+gUWOqt4sDC/JqPk6ZAjvXYcGEpErpPc95/fPwoZzj58G6 1KtYrtUEjNakMa5+kqcxq6sj7IoFZawLEQ/+kLrG4TYhcBKhzlZqeDieodgSgVbO/DoX UUhv0oxhbe3cFwP2X1ilLxro8CiqtkT1Xl3VvTvHtmeP9pUUTGkfKf3EyM4BpNRkVcOU dwM24uxLUvf1CVeWZe60rbvlYZzZG67M4MKtt/I8CoKUis6pRZzoaCSQOHTpP3/YrtZ7 In9IuNYMTpKv4WWACEjf9D21zki1IsOkELTIy9LggjdtBTFeeZwghLqtQwnE6yWA2xtj 9TLQ== 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=I4gtuqEeIk+gFW3SKHr/L+XpPeTk2VF2aQ4spVtTCos=; b=tpl+1PLh6XWn06U6Mxxse2mLMJbI+qudvwVRb3Op4L/QaEXLl7um0agetwQu9LoKXM gugmGd3rgWgcG54seOGdur2LX1Fej4WNbCHeoGH6UvYkcyHy3gLnVjvyPGd8iC9zCaOv EwpZBqkK+AotCZBhqfSSVOhB30GyR0ywOymsVPVbfa1UuqqeUQqX0j4xUlnHnGu11qH8 uEKoyg5F1M2tquH2JIWuU9QcxhohnPzwCK82KE6BfiFRYFkqttSzP2jMIKNUn8AI6zQV p6JoVPnyg9c5QrGfoZm8G/HAOtTC6yfXO4yYaCrZ607QM2K+MTaufHwBPB2z1Z3J6PCk qsLA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Mi4Buhq6; 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 l28si11094338pfg.215.2018.01.09.19.52.16; Tue, 09 Jan 2018 19:52:17 -0800 (PST) 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=Mi4Buhq6; 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 S934006AbeAJDwP (ORCPT + 28 others); Tue, 9 Jan 2018 22:52:15 -0500 Received: from mail-pg0-f65.google.com ([74.125.83.65]:44556 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965167AbeAJDsB (ORCPT ); Tue, 9 Jan 2018 22:48:01 -0500 Received: by mail-pg0-f65.google.com with SMTP id i5so9808594pgq.11 for ; Tue, 09 Jan 2018 19:48:01 -0800 (PST) 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=I4gtuqEeIk+gFW3SKHr/L+XpPeTk2VF2aQ4spVtTCos=; b=Mi4Buhq62JqiGIVWbriMPaYnL+2ddGP2E4CMO6fNcMgtjWSajnVVpsy2+7C/7Gw2te dS/39v4iPNdhMxgARXniNbwPWjg5co3R0/9w24CmSaCQZrTqq/qxReY/TkKrGRXnFjMN VkwtTh6tuzFwhND5pHT8IUtTzhmNGglXyOIoc= 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=I4gtuqEeIk+gFW3SKHr/L+XpPeTk2VF2aQ4spVtTCos=; b=a4eCvZ3LmJEG36flynyybF311bsrj6ag3zyA7Vh12tAgkq0aIzXs3Rt+YXSSxE2taj fgOWs818bNKmSuFasTFhsLbR33Zakc3B1LQeJHZh4IqK5bnHP8OZz8AUYPs1tcAaCyFt QRHExq7KdRgz+jQ5Xns7bP/qoWA8sB0bi5q/fu7Hdc4RH4ZdX+LwrqrYLwzUGOLJRyld 8nP6vsv1HR3Oy600tXvygsiG8Jewk5rJAevTqQY76bcGb3RwH6VYAqVnYHu7f43pVybC 7i5cuDiaObIdaJtuw1BL3bsr3h/I26scVhq4f2s5kVskE2hcSOTCUpBP2109hKwrvVEG idKQ== X-Gm-Message-State: AKGB3mI3l/xoGnvfNuOlgFJ2wcKLm2C//evr0WQmPZQ+0Bx2yuWvErrG C1Ex102RPz5cdl8g5apSCcuwo8K4Of8= X-Received: by 10.98.234.4 with SMTP id t4mr15667966pfh.74.1515556080769; Tue, 09 Jan 2018 19:48:00 -0800 (PST) Received: from localhost ([122.172.19.39]) by smtp.gmail.com with ESMTPSA id e8sm35021435pfk.6.2018.01.09.19.47.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 09 Jan 2018 19:48:00 -0800 (PST) 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 V6 03/13] drivers: Add boot constraints core Date: Wed, 10 Jan 2018 09:17:32 +0530 Message-Id: <02c600abd47f28f9c507ee1186440e51f985ba2e.1515554879.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.15.0.194.g9af6a3dea062 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 deferred probing. Tested-by: Rajendra Nayak Signed-off-by: Viresh Kumar --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/base/dd.c | 20 ++-- drivers/boot_constraint/Kconfig | 9 ++ drivers/boot_constraint/Makefile | 3 + drivers/boot_constraint/core.c | 219 +++++++++++++++++++++++++++++++++++++++ drivers/boot_constraint/core.h | 30 ++++++ include/linux/boot_constraint.h | 66 ++++++++++++ 8 files changed, 343 insertions(+), 7 deletions(-) create mode 100644 drivers/boot_constraint/Kconfig create mode 100644 drivers/boot_constraint/Makefile create mode 100644 drivers/boot_constraint/core.c create mode 100644 drivers/boot_constraint/core.h create mode 100644 include/linux/boot_constraint.h -- 2.15.0.194.g9af6a3dea062 diff --git a/drivers/Kconfig b/drivers/Kconfig index 152744c5ef0f..6aa1629423d4 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -5,6 +5,8 @@ source "drivers/amba/Kconfig" source "drivers/base/Kconfig" +source "drivers/boot_constraint/Kconfig" + source "drivers/bus/Kconfig" source "drivers/connector/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index e06f7f633f73..3a2774672e29 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ obj-$(CONFIG_PARPORT) += parport/ obj-$(CONFIG_NVM) += lightnvm/ obj-y += base/ block/ misc/ mfd/ nfc/ +obj-$(CONFIG_DEV_BOOT_CONSTRAINT) += boot_constraint/ obj-$(CONFIG_LIBNVDIMM) += nvdimm/ obj-$(CONFIG_DAX) += dax/ obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 533c82f55cea..dc89f98a2487 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -16,6 +16,7 @@ * Copyright (c) 2007-2009 Novell Inc. */ +#include #include #include #include @@ -419,15 +420,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/drivers/boot_constraint/Kconfig b/drivers/boot_constraint/Kconfig new file mode 100644 index 000000000000..9195f9a39fe2 --- /dev/null +++ b/drivers/boot_constraint/Kconfig @@ -0,0 +1,9 @@ +config DEV_BOOT_CONSTRAINT + 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. diff --git a/drivers/boot_constraint/Makefile b/drivers/boot_constraint/Makefile new file mode 100644 index 000000000000..0f2680177974 --- /dev/null +++ b/drivers/boot_constraint/Makefile @@ -0,0 +1,3 @@ +# Makefile for device boot constraints + +obj-y := core.o diff --git a/drivers/boot_constraint/core.c b/drivers/boot_constraint/core.c new file mode 100644 index 000000000000..45a0fbed1b11 --- /dev/null +++ b/drivers/boot_constraint/core.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This takes care of boot time device constraints, normally set by the + * Bootloader. + * + * Copyright (C) 2017 Linaro. + * Viresh Kumar + */ + +#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); +} + +/** + * dev_boot_constraint_add: Adds a boot constraint. + * + * @dev: Device for which the boot constraint is getting added. + * @info: Structure representing the boot constraint. + * + * This routine adds a single boot constraint for the device. This must be + * called before the device is probed by its driver, otherwise the boot + * constraint will never get removed and may result in unwanted behavior of the + * hardware. The boot constraint is removed by the driver core automatically + * after the device is probed (successfully or unsuccessfully). + * + * Return: 0 on success, and a negative error otherwise. + */ +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); +} + +/** + * dev_boot_constraints_remove: Removes all boot constraints of a device. + * + * @dev: Device for which the boot constraints are getting removed. + * + * This routine removes all the boot constraints that were previously added for + * the device. This is called directly by the driver core and should not be + * called by platform specific code. + */ +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/boot_constraint/core.h b/drivers/boot_constraint/core.h new file mode 100644 index 000000000000..1e87125de531 --- /dev/null +++ b/drivers/boot_constraint/core.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Linaro. + * Viresh Kumar + */ +#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; +}; +#endif /* _CORE_H */ diff --git a/include/linux/boot_constraint.h b/include/linux/boot_constraint.h new file mode 100644 index 000000000000..2ce62b7b3cc6 --- /dev/null +++ b/include/linux/boot_constraint.h @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Boot constraints header. + * + * Copyright (C) 2017 Linaro. + * Viresh Kumar + */ +#ifndef _LINUX_BOOT_CONSTRAINT_H +#define _LINUX_BOOT_CONSTRAINT_H + +#include +#include + +struct device; + +/** + * enum dev_boot_constraint_type - This defines different boot constraint types. + * + */ +enum dev_boot_constraint_type { + DEV_BOOT_CONSTRAINT_NONE, +}; + +/** + * struct dev_boot_constraint - This represents a single boot constraint. + * + * @type: This is boot constraint type (like: clk, supply, etc.). + * @data: This points to constraint type specific data (like: + * dev_boot_constraint_clk_info). + */ +struct dev_boot_constraint { + enum dev_boot_constraint_type type; + void *data; +}; + +/** + * struct dev_boot_constraint_info - This is used to add a single boot + * constraint. + * + * @constraint: This represents a single boot constraint. + * @free_resources: This callback is called by the boot constraint core after + * the constraint is removed. This is an optional field. + * @free_resources_data: This is data to be passed to free_resources() callback. + * This is an optional field. + */ +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_CONSTRAINT +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 0; } +static inline void dev_boot_constraints_remove(struct device *dev) {} +#endif /* CONFIG_DEV_BOOT_CONSTRAINT */ + +#endif /* _LINUX_BOOT_CONSTRAINT_H */