aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi.c
diff options
context:
space:
mode:
authorKirill Kapranov <kirill.kapranov@compulab.co.il>2018-08-13 19:48:10 +0300
committerMark Brown <broonie@kernel.org>2018-08-15 15:44:07 +0100
commit1a4327fbf4554d5b78d75b19a13d40d6de220159 (patch)
tree175422bba7026d50c01ae97cc6d0bbbbfaa975dc /drivers/spi/spi.c
parentspi: spi-mem: Constify spi_mem->name (diff)
downloadlinux-dev-1a4327fbf4554d5b78d75b19a13d40d6de220159.tar.xz
linux-dev-1a4327fbf4554d5b78d75b19a13d40d6de220159.zip
spi: fix IDR collision on systems with both fixed and dynamic SPI bus numbers
On systems where some controllers get a dynamic ID assigned and some have a fixed number (e.g. from ACPI tables), the current implementation might run into an IDR collision: in case of a fixed bus number is gotten by a driver (but not marked busy in IDR tree) and a driver with dynamic bus number gets the same ID and predictably fails. Fix this by means of checking-in fixed IDsin IDR as far as dynamic ones at the moment of the controller registration. Fixes: 9b61e302210e (spi: Pick spi bus number from Linux idr or spi alias) Signed-off-by: Kirill Kapranov <kirill.kapranov@compulab.co.il> Signed-off-by: Mark Brown <broonie@kernel.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r--drivers/spi/spi.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index ec395a6baf9c..a00d006d4c3a 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2170,6 +2170,15 @@ int spi_register_controller(struct spi_controller *ctlr)
if (WARN(id < 0, "couldn't get idr"))
return id;
ctlr->bus_num = id;
+ } else {
+ /* devices with a fixed bus num must check-in with the num */
+ mutex_lock(&board_lock);
+ id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
+ ctlr->bus_num + 1, GFP_KERNEL);
+ mutex_unlock(&board_lock);
+ if (WARN(id < 0, "couldn't get idr"))
+ return id == -ENOSPC ? -EBUSY : id;
+ ctlr->bus_num = id;
}
INIT_LIST_HEAD(&ctlr->queue);
spin_lock_init(&ctlr->queue_lock);