diff options
author | Geert Uytterhoeven <geert+renesas@glider.be> | 2018-08-21 05:53:03 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-08-28 15:46:27 -0400 |
commit | 04b2d03a75652bda989de1595048f0501dc0c0a0 (patch) | |
tree | d9fd964eeaa90b0884756a566039284158c683a7 | |
parent | 1a4327fbf4554d5b78d75b19a13d40d6de220159 (diff) |
spi: Fix double IDR allocation with DT aliases
If the SPI bus number is provided by a DT alias, idr_alloc() is called
twice, leading to:
WARNING: CPU: 1 PID: 1 at drivers/spi/spi.c:2179 spi_register_controller+0x11c/0x5d8
couldn't get idr
Fix this by moving the handling of fixed SPI bus numbers up, before the
DT handling code fills in ctlr->bus_num.
Fixes: 1a4327fbf4554d5b ("spi: fix IDR collision on systems with both fixed and dynamic SPI bus numbers")
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Tested-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/spi.c | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a00d006d4c3a..9da0bc5a036c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -2143,8 +2143,17 @@ int spi_register_controller(struct spi_controller *ctlr) | |||
2143 | */ | 2143 | */ |
2144 | if (ctlr->num_chipselect == 0) | 2144 | if (ctlr->num_chipselect == 0) |
2145 | return -EINVAL; | 2145 | return -EINVAL; |
2146 | /* allocate dynamic bus number using Linux idr */ | 2146 | if (ctlr->bus_num >= 0) { |
2147 | if ((ctlr->bus_num < 0) && ctlr->dev.of_node) { | 2147 | /* devices with a fixed bus num must check-in with the num */ |
2148 | mutex_lock(&board_lock); | ||
2149 | id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num, | ||
2150 | ctlr->bus_num + 1, GFP_KERNEL); | ||
2151 | mutex_unlock(&board_lock); | ||
2152 | if (WARN(id < 0, "couldn't get idr")) | ||
2153 | return id == -ENOSPC ? -EBUSY : id; | ||
2154 | ctlr->bus_num = id; | ||
2155 | } else if (ctlr->dev.of_node) { | ||
2156 | /* allocate dynamic bus number using Linux idr */ | ||
2148 | id = of_alias_get_id(ctlr->dev.of_node, "spi"); | 2157 | id = of_alias_get_id(ctlr->dev.of_node, "spi"); |
2149 | if (id >= 0) { | 2158 | if (id >= 0) { |
2150 | ctlr->bus_num = id; | 2159 | ctlr->bus_num = id; |
@@ -2170,15 +2179,6 @@ int spi_register_controller(struct spi_controller *ctlr) | |||
2170 | if (WARN(id < 0, "couldn't get idr")) | 2179 | if (WARN(id < 0, "couldn't get idr")) |
2171 | return id; | 2180 | return id; |
2172 | ctlr->bus_num = id; | 2181 | ctlr->bus_num = id; |
2173 | } else { | ||
2174 | /* devices with a fixed bus num must check-in with the num */ | ||
2175 | mutex_lock(&board_lock); | ||
2176 | id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num, | ||
2177 | ctlr->bus_num + 1, GFP_KERNEL); | ||
2178 | mutex_unlock(&board_lock); | ||
2179 | if (WARN(id < 0, "couldn't get idr")) | ||
2180 | return id == -ENOSPC ? -EBUSY : id; | ||
2181 | ctlr->bus_num = id; | ||
2182 | } | 2182 | } |
2183 | INIT_LIST_HEAD(&ctlr->queue); | 2183 | INIT_LIST_HEAD(&ctlr->queue); |
2184 | spin_lock_init(&ctlr->queue_lock); | 2184 | spin_lock_init(&ctlr->queue_lock); |