Merge tag 'spi-fix-v5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[linux-2.6-microblaze.git] / drivers / spi / spi.c
index 6626587..dc12af0 100644 (file)
@@ -475,6 +475,12 @@ static LIST_HEAD(spi_controller_list);
  */
 static DEFINE_MUTEX(board_lock);
 
+/*
+ * Prevents addition of devices with same chip select and
+ * addition of devices below an unregistering controller.
+ */
+static DEFINE_MUTEX(spi_add_lock);
+
 /**
  * spi_alloc_device - Allocate a new SPI device
  * @ctlr: Controller to which device is connected
@@ -554,7 +560,6 @@ static int spi_dev_check(struct device *dev, void *data)
  */
 int spi_add_device(struct spi_device *spi)
 {
-       static DEFINE_MUTEX(spi_add_lock);
        struct spi_controller *ctlr = spi->controller;
        struct device *dev = ctlr->dev.parent;
        int status;
@@ -582,6 +587,13 @@ int spi_add_device(struct spi_device *spi)
                goto done;
        }
 
+       /* Controller may unregister concurrently */
+       if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
+           !device_is_registered(&ctlr->dev)) {
+               status = -ENODEV;
+               goto done;
+       }
+
        /* Descriptors take precedence */
        if (ctlr->cs_gpiods)
                spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select];
@@ -2795,6 +2807,10 @@ void spi_unregister_controller(struct spi_controller *ctlr)
        struct spi_controller *found;
        int id = ctlr->bus_num;
 
+       /* Prevent addition of new devices, unregister existing ones */
+       if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
+               mutex_lock(&spi_add_lock);
+
        device_for_each_child(&ctlr->dev, NULL, __unregister);
 
        /* First make sure that this controller was ever added */
@@ -2815,6 +2831,9 @@ void spi_unregister_controller(struct spi_controller *ctlr)
        if (found == ctlr)
                idr_remove(&spi_master_idr, id);
        mutex_unlock(&board_lock);
+
+       if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
+               mutex_unlock(&spi_add_lock);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_controller);