Skip to content

Commit ddf75be

Browse files
l1kbroonie
authored andcommitted
spi: Prevent adding devices below an unregistering controller
CONFIG_OF_DYNAMIC and CONFIG_ACPI allow adding SPI devices at runtime using a DeviceTree overlay or DSDT patch. CONFIG_SPI_SLAVE allows the same via sysfs. But there are no precautions to prevent adding a device below a controller that's being removed. Such a device is unusable and may not even be able to unbind cleanly as it becomes inaccessible once the controller has been torn down. E.g. it is then impossible to quiesce the device's interrupt. of_spi_notify() and acpi_spi_notify() do hold a ref on the controller, but otherwise run lockless against spi_unregister_controller(). Fix by holding the spi_add_lock in spi_unregister_controller() and bailing out of spi_add_device() if the controller has been unregistered concurrently. Fixes: ce79d54 ("spi/of: Add OF notifier handler") Signed-off-by: Lukas Wunner <[email protected]> Cc: [email protected] # v3.19+ Cc: Geert Uytterhoeven <[email protected]> Cc: Octavian Purdila <[email protected]> Cc: Pantelis Antoniou <[email protected]> Link: https://lore.kernel.org/r/a8c3205088a969dc8410eec1eba9aface60f36af.1596451035.git.lukas@wunner.de Signed-off-by: Mark Brown <[email protected]>
1 parent 1d5cd4e commit ddf75be

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

drivers/spi/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,4 +1017,7 @@ config SPI_SLAVE_SYSTEM_CONTROL
10171017

10181018
endif # SPI_SLAVE
10191019

1020+
config SPI_DYNAMIC
1021+
def_bool ACPI || OF_DYNAMIC || SPI_SLAVE
1022+
10201023
endif # SPI

drivers/spi/spi.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,12 @@ static LIST_HEAD(spi_controller_list);
475475
*/
476476
static DEFINE_MUTEX(board_lock);
477477

478+
/*
479+
* Prevents addition of devices with same chip select and
480+
* addition of devices below an unregistering controller.
481+
*/
482+
static DEFINE_MUTEX(spi_add_lock);
483+
478484
/**
479485
* spi_alloc_device - Allocate a new SPI device
480486
* @ctlr: Controller to which device is connected
@@ -554,7 +560,6 @@ static int spi_dev_check(struct device *dev, void *data)
554560
*/
555561
int spi_add_device(struct spi_device *spi)
556562
{
557-
static DEFINE_MUTEX(spi_add_lock);
558563
struct spi_controller *ctlr = spi->controller;
559564
struct device *dev = ctlr->dev.parent;
560565
int status;
@@ -582,6 +587,13 @@ int spi_add_device(struct spi_device *spi)
582587
goto done;
583588
}
584589

590+
/* Controller may unregister concurrently */
591+
if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
592+
!device_is_registered(&ctlr->dev)) {
593+
status = -ENODEV;
594+
goto done;
595+
}
596+
585597
/* Descriptors take precedence */
586598
if (ctlr->cs_gpiods)
587599
spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select];
@@ -2797,6 +2809,10 @@ void spi_unregister_controller(struct spi_controller *ctlr)
27972809
struct spi_controller *found;
27982810
int id = ctlr->bus_num;
27992811

2812+
/* Prevent addition of new devices, unregister existing ones */
2813+
if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
2814+
mutex_lock(&spi_add_lock);
2815+
28002816
device_for_each_child(&ctlr->dev, NULL, __unregister);
28012817

28022818
/* First make sure that this controller was ever added */
@@ -2817,6 +2833,9 @@ void spi_unregister_controller(struct spi_controller *ctlr)
28172833
if (found == ctlr)
28182834
idr_remove(&spi_master_idr, id);
28192835
mutex_unlock(&board_lock);
2836+
2837+
if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
2838+
mutex_unlock(&spi_add_lock);
28202839
}
28212840
EXPORT_SYMBOL_GPL(spi_unregister_controller);
28222841

0 commit comments

Comments
 (0)