Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: Cleanup on failure of initial setup

Commit c7299fea6769 ("spi: Fix spi device unregister flow") changed the
SPI core's behavior if the ->setup() hook returns an error upon adding
an spi_device: Before, the ->cleanup() hook was invoked to free any
allocations that were made by ->setup(). With the commit, that's no
longer the case, so the ->setup() hook is expected to free the
allocations itself.

I've identified 5 drivers which depend on the old behavior and am fixing
them up hereinafter: spi-bitbang.c spi-fsl-spi.c spi-omap-uwire.c
spi-omap2-mcspi.c spi-pxa2xx.c

Importantly, ->setup() is not only invoked on spi_device *addition*:
It may subsequently be called to *change* SPI parameters. If changing
these SPI parameters fails, freeing memory allocations would be wrong.
That should only be done if the spi_device is finally destroyed.
I am therefore using a bool "initial_setup" in 4 of the affected drivers
to differentiate between the invocation on *adding* the spi_device and
any subsequent invocations: spi-bitbang.c spi-fsl-spi.c spi-omap-uwire.c
spi-omap2-mcspi.c

In spi-pxa2xx.c, it seems the ->setup() hook can only fail on spi_device
addition, not any subsequent calls. It therefore doesn't need the bool.

It's worth noting that 5 other drivers already perform a cleanup if the
->setup() hook fails. Before c7299fea6769, they caused a double-free
if ->setup() failed on spi_device addition. Since the commit, they're
fine. These drivers are: spi-mpc512x-psc.c spi-pl022.c spi-s3c64xx.c
spi-st-ssc4.c spi-tegra114.c

(spi-pxa2xx.c also already performs a cleanup, but only in one of
several error paths.)

Fixes: c7299fea6769 ("spi: Fix spi device unregister flow")
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Saravana Kannan <saravanak@google.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> # pxa2xx
Link: https://lore.kernel.org/r/f76a0599469f265b69c371538794101fa37b5536.1622149321.git.lukas@wunner.de
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Lukas Wunner and committed by
Mark Brown
2ec6f20b 13817d46

+54 -19
+14 -4
drivers/spi/spi-bitbang.c
··· 184 184 { 185 185 struct spi_bitbang_cs *cs = spi->controller_state; 186 186 struct spi_bitbang *bitbang; 187 + bool initial_setup = false; 188 + int retval; 187 189 188 190 bitbang = spi_master_get_devdata(spi->master); 189 191 ··· 194 192 if (!cs) 195 193 return -ENOMEM; 196 194 spi->controller_state = cs; 195 + initial_setup = true; 197 196 } 198 197 199 198 /* per-word shift register access, in hardware or bitbanging */ 200 199 cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)]; 201 - if (!cs->txrx_word) 202 - return -EINVAL; 200 + if (!cs->txrx_word) { 201 + retval = -EINVAL; 202 + goto err_free; 203 + } 203 204 204 205 if (bitbang->setup_transfer) { 205 - int retval = bitbang->setup_transfer(spi, NULL); 206 + retval = bitbang->setup_transfer(spi, NULL); 206 207 if (retval < 0) 207 - return retval; 208 + goto err_free; 208 209 } 209 210 210 211 dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); 211 212 212 213 return 0; 214 + 215 + err_free: 216 + if (initial_setup) 217 + kfree(cs); 218 + return retval; 213 219 } 214 220 EXPORT_SYMBOL_GPL(spi_bitbang_setup); 215 221
+4
drivers/spi/spi-fsl-spi.c
··· 440 440 { 441 441 struct mpc8xxx_spi *mpc8xxx_spi; 442 442 struct fsl_spi_reg __iomem *reg_base; 443 + bool initial_setup = false; 443 444 int retval; 444 445 u32 hw_mode; 445 446 struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); ··· 453 452 if (!cs) 454 453 return -ENOMEM; 455 454 spi_set_ctldata(spi, cs); 455 + initial_setup = true; 456 456 } 457 457 mpc8xxx_spi = spi_master_get_devdata(spi->master); 458 458 ··· 477 475 retval = fsl_spi_setup_transfer(spi, NULL); 478 476 if (retval < 0) { 479 477 cs->hw_mode = hw_mode; /* Restore settings */ 478 + if (initial_setup) 479 + kfree(cs); 480 480 return retval; 481 481 } 482 482
+8 -1
drivers/spi/spi-omap-uwire.c
··· 424 424 static int uwire_setup(struct spi_device *spi) 425 425 { 426 426 struct uwire_state *ust = spi->controller_state; 427 + bool initial_setup = false; 428 + int status; 427 429 428 430 if (ust == NULL) { 429 431 ust = kzalloc(sizeof(*ust), GFP_KERNEL); 430 432 if (ust == NULL) 431 433 return -ENOMEM; 432 434 spi->controller_state = ust; 435 + initial_setup = true; 433 436 } 434 437 435 - return uwire_setup_transfer(spi, NULL); 438 + status = uwire_setup_transfer(spi, NULL); 439 + if (status && initial_setup) 440 + kfree(ust); 441 + 442 + return status; 436 443 } 437 444 438 445 static void uwire_cleanup(struct spi_device *spi)
+20 -13
drivers/spi/spi-omap2-mcspi.c
··· 1032 1032 } 1033 1033 } 1034 1034 1035 + static void omap2_mcspi_cleanup(struct spi_device *spi) 1036 + { 1037 + struct omap2_mcspi_cs *cs; 1038 + 1039 + if (spi->controller_state) { 1040 + /* Unlink controller state from context save list */ 1041 + cs = spi->controller_state; 1042 + list_del(&cs->node); 1043 + 1044 + kfree(cs); 1045 + } 1046 + } 1047 + 1035 1048 static int omap2_mcspi_setup(struct spi_device *spi) 1036 1049 { 1050 + bool initial_setup = false; 1037 1051 int ret; 1038 1052 struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 1039 1053 struct omap2_mcspi_regs *ctx = &mcspi->ctx; ··· 1065 1051 spi->controller_state = cs; 1066 1052 /* Link this to context save list */ 1067 1053 list_add_tail(&cs->node, &ctx->cs); 1054 + initial_setup = true; 1068 1055 } 1069 1056 1070 1057 ret = pm_runtime_get_sync(mcspi->dev); 1071 1058 if (ret < 0) { 1072 1059 pm_runtime_put_noidle(mcspi->dev); 1060 + if (initial_setup) 1061 + omap2_mcspi_cleanup(spi); 1073 1062 1074 1063 return ret; 1075 1064 } 1076 1065 1077 1066 ret = omap2_mcspi_setup_transfer(spi, NULL); 1067 + if (ret && initial_setup) 1068 + omap2_mcspi_cleanup(spi); 1069 + 1078 1070 pm_runtime_mark_last_busy(mcspi->dev); 1079 1071 pm_runtime_put_autosuspend(mcspi->dev); 1080 1072 1081 1073 return ret; 1082 - } 1083 - 1084 - static void omap2_mcspi_cleanup(struct spi_device *spi) 1085 - { 1086 - struct omap2_mcspi_cs *cs; 1087 - 1088 - if (spi->controller_state) { 1089 - /* Unlink controller state from context save list */ 1090 - cs = spi->controller_state; 1091 - list_del(&cs->node); 1092 - 1093 - kfree(cs); 1094 - } 1095 1074 } 1096 1075 1097 1076 static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
+8 -1
drivers/spi/spi-pxa2xx.c
··· 1254 1254 chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; 1255 1255 1256 1256 err = gpiod_direction_output(gpiod, !chip->gpio_cs_inverted); 1257 + if (err) 1258 + gpiod_put(chip->gpiod_cs); 1257 1259 } 1258 1260 1259 1261 return err; ··· 1269 1267 struct driver_data *drv_data = 1270 1268 spi_controller_get_devdata(spi->controller); 1271 1269 uint tx_thres, tx_hi_thres, rx_thres; 1270 + int err; 1272 1271 1273 1272 switch (drv_data->ssp_type) { 1274 1273 case QUARK_X1000_SSP: ··· 1416 1413 if (drv_data->ssp_type == CE4100_SSP) 1417 1414 return 0; 1418 1415 1419 - return setup_cs(spi, chip, chip_info); 1416 + err = setup_cs(spi, chip, chip_info); 1417 + if (err) 1418 + kfree(chip); 1419 + 1420 + return err; 1420 1421 } 1421 1422 1422 1423 static void cleanup(struct spi_device *spi)