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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'spi-fix-v7.0-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
"There's a relatively large but ultimately simple fix for spidev here
which addresses some ABBA races by simplifying down to just using a
single lock, it's not clear to me that there was ever any benefit in
having the two separate locks in the first place.

We also have simple missing error check fix in in the wpcm-fiu driver"

* tag 'spi-fix-v7.0-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
spi: spidev: fix lock inversion between spi_lock and buf_lock
spi: wpcm-fiu: Fix potential NULL pointer dereference in wpcm_fiu_probe()

+23 -42
+1 -1
drivers/spi/spi-wpcm-fiu.c
··· 459 459 460 460 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); 461 461 fiu->memory = devm_ioremap_resource(dev, res); 462 - fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); 463 462 if (IS_ERR(fiu->memory)) 464 463 return dev_err_probe(dev, PTR_ERR(fiu->memory), 465 464 "Failed to map flash memory window\n"); 466 465 466 + fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); 467 467 fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm"); 468 468 469 469 wpcm_fiu_hw_init(fiu);
+22 -41
drivers/spi/spidev.c
··· 74 74 struct list_head device_entry; 75 75 76 76 /* TX/RX buffers are NULL unless this device is open (users > 0) */ 77 - struct mutex buf_lock; 78 77 unsigned users; 79 78 u8 *tx_buffer; 80 79 u8 *rx_buffer; ··· 101 102 return status; 102 103 } 103 104 104 - static ssize_t 105 - spidev_sync(struct spidev_data *spidev, struct spi_message *message) 106 - { 107 - ssize_t status; 108 - struct spi_device *spi; 109 - 110 - mutex_lock(&spidev->spi_lock); 111 - spi = spidev->spi; 112 - 113 - if (spi == NULL) 114 - status = -ESHUTDOWN; 115 - else 116 - status = spidev_sync_unlocked(spi, message); 117 - 118 - mutex_unlock(&spidev->spi_lock); 119 - return status; 120 - } 121 - 122 105 static inline ssize_t 123 106 spidev_sync_write(struct spidev_data *spidev, size_t len) 124 107 { ··· 113 132 114 133 spi_message_init(&m); 115 134 spi_message_add_tail(&t, &m); 116 - return spidev_sync(spidev, &m); 135 + 136 + return spidev_sync_unlocked(spidev->spi, &m); 117 137 } 118 138 119 139 static inline ssize_t ··· 129 147 130 148 spi_message_init(&m); 131 149 spi_message_add_tail(&t, &m); 132 - return spidev_sync(spidev, &m); 150 + 151 + return spidev_sync_unlocked(spidev->spi, &m); 133 152 } 134 153 135 154 /*-------------------------------------------------------------------------*/ ··· 140 157 spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) 141 158 { 142 159 struct spidev_data *spidev; 143 - ssize_t status; 160 + ssize_t status = -ESHUTDOWN; 144 161 145 162 /* chipselect only toggles at start or end of operation */ 146 163 if (count > bufsiz) ··· 148 165 149 166 spidev = filp->private_data; 150 167 151 - mutex_lock(&spidev->buf_lock); 168 + mutex_lock(&spidev->spi_lock); 169 + 170 + if (spidev->spi == NULL) 171 + goto err_spi_removed; 172 + 152 173 status = spidev_sync_read(spidev, count); 153 174 if (status > 0) { 154 175 unsigned long missing; ··· 163 176 else 164 177 status = status - missing; 165 178 } 166 - mutex_unlock(&spidev->buf_lock); 179 + 180 + err_spi_removed: 181 + mutex_unlock(&spidev->spi_lock); 167 182 168 183 return status; 169 184 } ··· 176 187 size_t count, loff_t *f_pos) 177 188 { 178 189 struct spidev_data *spidev; 179 - ssize_t status; 190 + ssize_t status = -ESHUTDOWN; 180 191 unsigned long missing; 181 192 182 193 /* chipselect only toggles at start or end of operation */ ··· 185 196 186 197 spidev = filp->private_data; 187 198 188 - mutex_lock(&spidev->buf_lock); 199 + mutex_lock(&spidev->spi_lock); 200 + 201 + if (spidev->spi == NULL) 202 + goto err_spi_removed; 203 + 189 204 missing = copy_from_user(spidev->tx_buffer, buf, count); 190 205 if (missing == 0) 191 206 status = spidev_sync_write(spidev, count); 192 207 else 193 208 status = -EFAULT; 194 - mutex_unlock(&spidev->buf_lock); 209 + 210 + err_spi_removed: 211 + mutex_unlock(&spidev->spi_lock); 195 212 196 213 return status; 197 214 } ··· 374 379 375 380 ctlr = spi->controller; 376 381 377 - /* use the buffer lock here for triple duty: 378 - * - prevent I/O (from us) so calling spi_setup() is safe; 379 - * - prevent concurrent SPI_IOC_WR_* from morphing 380 - * data fields while SPI_IOC_RD_* reads them; 381 - * - SPI_IOC_MESSAGE needs the buffer locked "normally". 382 - */ 383 - mutex_lock(&spidev->buf_lock); 384 - 385 382 switch (cmd) { 386 383 /* read requests */ 387 384 case SPI_IOC_RD_MODE: ··· 497 510 break; 498 511 } 499 512 500 - mutex_unlock(&spidev->buf_lock); 501 513 spi_dev_put(spi); 502 514 mutex_unlock(&spidev->spi_lock); 503 515 return retval; ··· 527 541 return -ESHUTDOWN; 528 542 } 529 543 530 - /* SPI_IOC_MESSAGE needs the buffer locked "normally" */ 531 - mutex_lock(&spidev->buf_lock); 532 - 533 544 /* Check message and copy into scratch area */ 534 545 ioc = spidev_get_ioc_message(cmd, u_ioc, &n_ioc); 535 546 if (IS_ERR(ioc)) { ··· 547 564 kfree(ioc); 548 565 549 566 done: 550 - mutex_unlock(&spidev->buf_lock); 551 567 spi_dev_put(spi); 552 568 mutex_unlock(&spidev->spi_lock); 553 569 return retval; ··· 784 802 /* Initialize the driver data */ 785 803 spidev->spi = spi; 786 804 mutex_init(&spidev->spi_lock); 787 - mutex_init(&spidev->buf_lock); 788 805 789 806 INIT_LIST_HEAD(&spidev->device_entry); 790 807