lkml.org 
[lkml]   [2021]   [Mar]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] spi: ensure timely release of driver-allocated resources
More and more drivers rely on devres to manage their resources, however
if bus' probe() and release() methods are not trivial and control some
of resources as well (for example enable or disable clocks, or attach
device to a power domain), we need to make sure that driver-allocated
resources are released immediately after driver's remove() method
returns, and not postponed until driver core gets around to releasing
resources. To fix that we open a new devres group before calling
driver's probe() and explicitly release it when we return from driver's
remove().

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---

Note that this is not SPI-specific issue. I already send a similar
patch for I2C and will be sending more.

drivers/spi/spi.c | 25 +++++++++++++++++++++++--
include/linux/spi/spi.h | 4 ++++
2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index c19a09201358..7c369cebebbd 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -421,29 +421,50 @@ static int spi_probe(struct device *dev)
if (ret)
return ret;

+ spi->devres_group_id = devres_open_group(dev, NULL, GFP_KERNEL);
+ if (!spi->devres_group_id) {
+ ret = -ENOMEM;
+ goto err_detach_pm_domain;
+ }
+
if (sdrv->probe) {
ret = sdrv->probe(spi);
if (ret)
- dev_pm_domain_detach(dev, true);
+ goto err_release_driver_resources;
}

+ /*
+ * Note that we are not closing the devres group opened above so
+ * even resources that were attached to the device after probe has
+ * run are released when spi_remove() is executed. This is needed as
+ * some drivers might allocate additional resources.
+ */
+
+ return 0;
+
+err_release_driver_resources:
+ devres_release_group(dev, spi->devres_group_id);
+err_detach_pm_domain:
+ dev_pm_domain_detach(dev, true);
return ret;
}

static int spi_remove(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
+ struct spi_device *spi = to_spi_device(dev);

if (sdrv->remove) {
int ret;

- ret = sdrv->remove(to_spi_device(dev));
+ ret = sdrv->remove(spi);
if (ret)
dev_warn(dev,
"Failed to unbind driver (%pe), ignoring\n",
ERR_PTR(ret));
}

+ devres_release_group(dev, spi->devres_group_id);
dev_pm_domain_detach(dev, true);

return 0;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index aa09fdc8042d..969dd8ccc657 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -144,6 +144,8 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
* not using a GPIO line)
* @word_delay: delay to be inserted between consecutive
* words of a transfer
+ * @devres_group_id: id of the devres group that will be created for resources
+ * acquired when probing this device.
*
* @statistics: statistics for the spi_device
*
@@ -195,6 +197,8 @@ struct spi_device {
struct gpio_desc *cs_gpiod; /* chip select gpio desc */
struct spi_delay word_delay; /* inter-word delay */

+ void *devres_group_id;
+
/* the statistics */
struct spi_statistics statistics;

--
2.31.0.rc2.261.g7f71774620-goog

--
Dmitry

\
 
 \ /
  Last update: 2021-03-22 02:44    [W:0.061 / U:4.172 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site