From 53c7626356c7584e82510d86394a6dcd80525614 Mon Sep 17 00:00:00 2001 From: Frédéric Danis Date: Wed, 11 Oct 2017 10:32:13 +0200 Subject: serdev: Add ACPI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch allows SerDev module to manage serial devices declared as attached to an UART in ACPI table. acpi_serdev_add_device() callback will only take into account entries without enumerated flag set. This flags is set for all entries during ACPI scan, except for SPI and I2C serial devices, and for UART with 2nd patch in the series. Check if a serdev device as been allocated during acpi_walk_namespace() to prevent serdev controller registration instead of the tty-class device. Signed-off-by: Frédéric Danis Reviewed-by: Rob Herring Reviewed-by: Sebastian Reichel Reviewed-by: Johan Hovold Acked-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 100 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 5 deletions(-) (limited to 'drivers/tty/serdev/core.c') diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index c68fb3a8ea1c..ec113e39993f 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -14,6 +14,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -49,13 +50,22 @@ static const struct device_type serdev_ctrl_type = { static int serdev_device_match(struct device *dev, struct device_driver *drv) { - /* TODO: ACPI and platform matching */ + /* TODO: platform matching */ + if (acpi_driver_match_device(dev, drv)) + return 1; + return of_driver_match_device(dev, drv); } static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env) { - /* TODO: ACPI and platform modalias */ + int rc; + + /* TODO: platform modalias */ + rc = acpi_device_uevent_modalias(dev, env); + if (rc != -ENODEV) + return rc; + return of_device_uevent_modalias(dev, env); } @@ -260,6 +270,12 @@ static int serdev_drv_remove(struct device *dev) static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { + int len; + + len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); + if (len != -ENODEV) + return len; + return of_device_modalias(dev, buf, PAGE_SIZE); } DEVICE_ATTR_RO(modalias); @@ -385,6 +401,75 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl) return 0; } +#ifdef CONFIG_ACPI +static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl, + struct acpi_device *adev) +{ + struct serdev_device *serdev = NULL; + int err; + + if (acpi_bus_get_status(adev) || !adev->status.present || + acpi_device_enumerated(adev)) + return AE_OK; + + serdev = serdev_device_alloc(ctrl); + if (!serdev) { + dev_err(&ctrl->dev, "failed to allocate serdev device for %s\n", + dev_name(&adev->dev)); + return AE_NO_MEMORY; + } + + ACPI_COMPANION_SET(&serdev->dev, adev); + acpi_device_set_enumerated(adev); + + err = serdev_device_add(serdev); + if (err) { + dev_err(&serdev->dev, + "failure adding ACPI serdev device. status %d\n", err); + serdev_device_put(serdev); + } + + return AE_OK; +} + +static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct serdev_controller *ctrl = data; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + return acpi_serdev_register_device(ctrl, adev); +} + +static int acpi_serdev_register_devices(struct serdev_controller *ctrl) +{ + acpi_status status; + acpi_handle handle; + + handle = ACPI_HANDLE(ctrl->dev.parent); + if (!handle) + return -ENODEV; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_serdev_add_device, NULL, ctrl, NULL); + if (ACPI_FAILURE(status)) + dev_dbg(&ctrl->dev, "failed to enumerate serdev slaves\n"); + + if (!ctrl->serdev) + return -ENODEV; + + return 0; +} +#else +static inline int acpi_serdev_register_devices(struct serdev_controller *ctrl) +{ + return -ENODEV; +} +#endif /* CONFIG_ACPI */ + /** * serdev_controller_add() - Add an serdev controller * @ctrl: controller to be registered. @@ -394,7 +479,7 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl) */ int serdev_controller_add(struct serdev_controller *ctrl) { - int ret; + int ret_of, ret_acpi, ret; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) @@ -404,9 +489,14 @@ int serdev_controller_add(struct serdev_controller *ctrl) if (ret) return ret; - ret = of_serdev_register_devices(ctrl); - if (ret) + ret_of = of_serdev_register_devices(ctrl); + ret_acpi = acpi_serdev_register_devices(ctrl); + if (ret_of && ret_acpi) { + dev_dbg(&ctrl->dev, "no devices registered: of:%d acpi:%d\n", + ret_of, ret_acpi); + ret = -ENODEV; goto out_dev_del; + } dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n", ctrl->nr, &ctrl->dev); -- cgit From 08fcee289f341786eb3b44e5f2d1dc850943238e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Oct 2017 18:09:49 +0200 Subject: serdev: fix registration of second slave Serdev currently only supports a single slave device, but the required sanity checks to prevent further registration attempts were missing. If a serial-port node has two child nodes with compatible properties, the OF code would try to register two slave devices using the same id and name. Driver core will not allow this (and there will be loud complaints), but the controller's slave pointer would already have been set to address of the soon to be deallocated second struct serdev_device. As the first slave device remains registered, this can lead to later use-after-free issues when the slave callbacks are accessed. Note that while the serdev registration helpers are exported, they are typically only called by serdev core. Any other (out-of-tree) callers must serialise registration and deregistration themselves. Fixes: cd6484e1830b ("serdev: Introduce new bus for serial attached devices") Cc: stable # 4.11 Cc: Rob Herring Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/tty/serdev/core.c') diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index ec113e39993f..dde2ddc5967d 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -75,21 +75,32 @@ static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env) */ int serdev_device_add(struct serdev_device *serdev) { + struct serdev_controller *ctrl = serdev->ctrl; struct device *parent = serdev->dev.parent; int err; dev_set_name(&serdev->dev, "%s-%d", dev_name(parent), serdev->nr); + /* Only a single slave device is currently supported. */ + if (ctrl->serdev) { + dev_err(&serdev->dev, "controller busy\n"); + return -EBUSY; + } + ctrl->serdev = serdev; + err = device_add(&serdev->dev); if (err < 0) { dev_err(&serdev->dev, "Can't add %s, status %d\n", dev_name(&serdev->dev), err); - goto err_device_add; + goto err_clear_serdev; } dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev)); -err_device_add: + return 0; + +err_clear_serdev: + ctrl->serdev = NULL; return err; } EXPORT_SYMBOL_GPL(serdev_device_add); @@ -100,7 +111,10 @@ EXPORT_SYMBOL_GPL(serdev_device_add); */ void serdev_device_remove(struct serdev_device *serdev) { + struct serdev_controller *ctrl = serdev->ctrl; + device_unregister(&serdev->dev); + ctrl->serdev = NULL; } EXPORT_SYMBOL_GPL(serdev_device_remove); @@ -311,7 +325,6 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl) return NULL; serdev->ctrl = ctrl; - ctrl->serdev = serdev; device_initialize(&serdev->dev); serdev->dev.parent = &ctrl->dev; serdev->dev.bus = &serdev_bus_type; -- cgit From 978d6fac5d0617c9722ae1db1accee46776f4400 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 12 Oct 2017 15:28:18 +0200 Subject: serdev: fix controller-allocation error handling Reorder controller initialisation so that in the unlikely event that id allocation fails, we don't end up releasing id 0 in the destructor. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/tty/serdev/core.c') diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index dde2ddc5967d..4d662d1f4784 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -358,26 +358,31 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent, if (!ctrl) return NULL; - device_initialize(&ctrl->dev); - ctrl->dev.type = &serdev_ctrl_type; - ctrl->dev.bus = &serdev_bus_type; - ctrl->dev.parent = parent; - ctrl->dev.of_node = parent->of_node; - serdev_controller_set_drvdata(ctrl, &ctrl[1]); - id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL); if (id < 0) { dev_err(parent, "unable to allocate serdev controller identifier.\n"); - serdev_controller_put(ctrl); - return NULL; + goto err_free; } ctrl->nr = id; + + device_initialize(&ctrl->dev); + ctrl->dev.type = &serdev_ctrl_type; + ctrl->dev.bus = &serdev_bus_type; + ctrl->dev.parent = parent; + ctrl->dev.of_node = parent->of_node; + serdev_controller_set_drvdata(ctrl, &ctrl[1]); + dev_set_name(&ctrl->dev, "serial%d", id); dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id); return ctrl; + +err_free: + kfree(ctrl); + + return NULL; } EXPORT_SYMBOL_GPL(serdev_controller_alloc); -- cgit From e3b3d0f549c1d19b94e6ac55c66643166ea649ef Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 6 Nov 2017 18:11:51 +0100 Subject: tty: add SPDX identifiers to all remaining files in drivers/tty/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's good to have SPDX identifiers in all files to make it easier to audit the kernel tree for correct licenses. Update the drivers/tty files files with the correct SPDX license identifier based on the license text in the file itself. The SPDX identifier is a legally binding shorthand, which can be used instead of the full boiler plate text. This work is based on a script and data from Thomas Gleixner, Philippe Ombredanne, and Kate Stewart. Cc: Jiri Slaby Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Chris Metcalf Cc: Jiri Kosina Cc: David Sterba Cc: James Hogan Cc: Rob Herring Cc: Eric Anholt Cc: Stefan Wahren Cc: Florian Fainelli Cc: Ray Jui Cc: Scott Branden Cc: bcm-kernel-feedback-list@broadcom.com Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: Joachim Eastwood Cc: Matthias Brugger Cc: Masahiro Yamada Cc: Tobias Klauser Cc: Russell King Cc: Vineet Gupta Cc: Richard Genoud Cc: Alexander Shiyan Cc: Baruch Siach Cc: "Maciej W. Rozycki" Cc: "Uwe Kleine-König" Cc: Pat Gefre Cc: "Guilherme G. Piccoli" Cc: Jason Wessel Cc: Vladimir Zapolskiy Cc: Sylvain Lemieux Cc: Carlo Caione Cc: Kevin Hilman Cc: Liviu Dudau Cc: Sudeep Holla Cc: Lorenzo Pieralisi Cc: Andy Gross Cc: David Brown Cc: "Andreas Färber" Cc: Kevin Cernekee Cc: Laxman Dewangan Cc: Thierry Reding Cc: Jonathan Hunter Cc: Barry Song Cc: Patrice Chotard Cc: Maxime Coquelin Cc: Alexandre Torgue Cc: "David S. Miller" Cc: Peter Korsgaard Cc: Timur Tabi Cc: Tony Prisk Cc: Michal Simek Cc: "Sören Brinkmann" Cc: Thomas Gleixner Cc: Kate Stewart Cc: Philippe Ombredanne Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty/serdev/core.c') diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 4d662d1f4784..2aece10ef912 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring * -- cgit From 4e17ff37f185c4abba98afe372cadeac368cde89 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 6 Nov 2017 18:11:54 +0100 Subject: tty: serdev: Remove redundant license text Now that the SPDX tag is in all tty files, that identifies the license in a specific and legally-defined manner. So the extra GPL text wording can be removed as it is no longer needed at all. This is done on a quest to remove the 700+ different ways that files in the kernel describe the GPL license text. And there's unneeded stuff like the address (sometimes incorrect) for the FSF which is never needed. No copyright headers or other non-license-description text was removed. Cc: Rob Herring Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/tty/serdev/core.c') diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 2aece10ef912..1bef39828ca7 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -4,15 +4,6 @@ * * Based on drivers/spmi/spmi.c: * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include -- cgit