Commit c757fc92 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'spi-fix-v6.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:

 - Fixes for long standing issues with accesses to spidev->spi during
   teardown in the spidev userspace driver.

 - Rename the newly added spi-cs-setup-ns DT property to be more in line
   with our other delay properties before it becomes ABI.

 - A few driver specific fixes.

* tag 'spi-fix-v6.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: spidev: remove debug messages that access spidev->spi without locking
  spi: spidev: fix a race condition when accessing spidev->spi
  spi: Rename spi-cs-setup-ns property to spi-cs-setup-delay-ns
  spi: dt-bindings: Rename spi-cs-setup-ns to spi-cs-setup-delay-ns
  spi: cadence: Fix busy cycles calculation
  spi: mediatek: Enable irq before the spi registration
parents cf9668a2 b442990d
...@@ -44,9 +44,9 @@ properties: ...@@ -44,9 +44,9 @@ properties:
description: description:
Maximum SPI clocking speed of the device in Hz. Maximum SPI clocking speed of the device in Hz.
spi-cs-setup-ns: spi-cs-setup-delay-ns:
description: description:
Delay in nanosecods to be introduced by the controller after CS is Delay in nanoseconds to be introduced by the controller after CS is
asserted. asserted.
spi-rx-bus-width: spi-rx-bus-width:
......
...@@ -177,7 +177,10 @@ ...@@ -177,7 +177,10 @@
#define CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op) ( \ #define CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op) ( \
FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_DCNT_H, \ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_DCNT_H, \
((op)->data.nbytes >> 16) & 0xffff) | \ ((op)->data.nbytes >> 16) & 0xffff) | \
FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_NUM_OF_DUMMY, (op)->dummy.nbytes * 8)) FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_NUM_OF_DUMMY, \
(op)->dummy.buswidth != 0 ? \
(((op)->dummy.nbytes * 8) / (op)->dummy.buswidth) : \
0))
#define CDNS_XSPI_CMD_FLD_DSEQ_CMD_4(op, chipsel) ( \ #define CDNS_XSPI_CMD_FLD_DSEQ_CMD_4(op, chipsel) ( \
FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_BANK, chipsel) | \ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_BANK, chipsel) | \
......
...@@ -1253,6 +1253,11 @@ static int mtk_spi_probe(struct platform_device *pdev) ...@@ -1253,6 +1253,11 @@ static int mtk_spi_probe(struct platform_device *pdev)
dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n", dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n",
addr_bits, ret); addr_bits, ret);
ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
IRQF_TRIGGER_NONE, dev_name(dev), master);
if (ret)
return dev_err_probe(dev, ret, "failed to register irq\n");
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = devm_spi_register_master(dev, master); ret = devm_spi_register_master(dev, master);
...@@ -1261,13 +1266,6 @@ static int mtk_spi_probe(struct platform_device *pdev) ...@@ -1261,13 +1266,6 @@ static int mtk_spi_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret, "failed to register master\n"); return dev_err_probe(dev, ret, "failed to register master\n");
} }
ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
IRQF_TRIGGER_NONE, dev_name(dev), master);
if (ret) {
pm_runtime_disable(dev);
return dev_err_probe(dev, ret, "failed to register irq\n");
}
return 0; return 0;
} }
......
...@@ -2310,7 +2310,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, ...@@ -2310,7 +2310,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
if (!of_property_read_u32(nc, "spi-max-frequency", &value)) if (!of_property_read_u32(nc, "spi-max-frequency", &value))
spi->max_speed_hz = value; spi->max_speed_hz = value;
if (!of_property_read_u16(nc, "spi-cs-setup-ns", &cs_setup)) { if (!of_property_read_u16(nc, "spi-cs-setup-delay-ns", &cs_setup)) {
spi->cs_setup.value = cs_setup; spi->cs_setup.value = cs_setup;
spi->cs_setup.unit = SPI_DELAY_UNIT_NSECS; spi->cs_setup.unit = SPI_DELAY_UNIT_NSECS;
} }
......
...@@ -68,7 +68,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256); ...@@ -68,7 +68,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
struct spidev_data { struct spidev_data {
dev_t devt; dev_t devt;
spinlock_t spi_lock; struct mutex spi_lock;
struct spi_device *spi; struct spi_device *spi;
struct list_head device_entry; struct list_head device_entry;
...@@ -95,9 +95,8 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message) ...@@ -95,9 +95,8 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
int status; int status;
struct spi_device *spi; struct spi_device *spi;
spin_lock_irq(&spidev->spi_lock); mutex_lock(&spidev->spi_lock);
spi = spidev->spi; spi = spidev->spi;
spin_unlock_irq(&spidev->spi_lock);
if (spi == NULL) if (spi == NULL)
status = -ESHUTDOWN; status = -ESHUTDOWN;
...@@ -107,6 +106,7 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message) ...@@ -107,6 +106,7 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
if (status == 0) if (status == 0)
status = message->actual_length; status = message->actual_length;
mutex_unlock(&spidev->spi_lock);
return status; return status;
} }
...@@ -359,12 +359,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -359,12 +359,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
* we issue this ioctl. * we issue this ioctl.
*/ */
spidev = filp->private_data; spidev = filp->private_data;
spin_lock_irq(&spidev->spi_lock); mutex_lock(&spidev->spi_lock);
spi = spi_dev_get(spidev->spi); spi = spi_dev_get(spidev->spi);
spin_unlock_irq(&spidev->spi_lock); if (spi == NULL) {
mutex_unlock(&spidev->spi_lock);
if (spi == NULL)
return -ESHUTDOWN; return -ESHUTDOWN;
}
/* use the buffer lock here for triple duty: /* use the buffer lock here for triple duty:
* - prevent I/O (from us) so calling spi_setup() is safe; * - prevent I/O (from us) so calling spi_setup() is safe;
...@@ -508,6 +508,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -508,6 +508,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
mutex_unlock(&spidev->buf_lock); mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi); spi_dev_put(spi);
mutex_unlock(&spidev->spi_lock);
return retval; return retval;
} }
...@@ -529,12 +530,12 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, ...@@ -529,12 +530,12 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
* we issue this ioctl. * we issue this ioctl.
*/ */
spidev = filp->private_data; spidev = filp->private_data;
spin_lock_irq(&spidev->spi_lock); mutex_lock(&spidev->spi_lock);
spi = spi_dev_get(spidev->spi); spi = spi_dev_get(spidev->spi);
spin_unlock_irq(&spidev->spi_lock); if (spi == NULL) {
mutex_unlock(&spidev->spi_lock);
if (spi == NULL)
return -ESHUTDOWN; return -ESHUTDOWN;
}
/* SPI_IOC_MESSAGE needs the buffer locked "normally" */ /* SPI_IOC_MESSAGE needs the buffer locked "normally" */
mutex_lock(&spidev->buf_lock); mutex_lock(&spidev->buf_lock);
...@@ -561,6 +562,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd, ...@@ -561,6 +562,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
done: done:
mutex_unlock(&spidev->buf_lock); mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi); spi_dev_put(spi);
mutex_unlock(&spidev->spi_lock);
return retval; return retval;
} }
...@@ -601,7 +603,6 @@ static int spidev_open(struct inode *inode, struct file *filp) ...@@ -601,7 +603,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
if (!spidev->tx_buffer) { if (!spidev->tx_buffer) {
spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spidev->tx_buffer) { if (!spidev->tx_buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM; status = -ENOMEM;
goto err_find_dev; goto err_find_dev;
} }
...@@ -610,7 +611,6 @@ static int spidev_open(struct inode *inode, struct file *filp) ...@@ -610,7 +611,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
if (!spidev->rx_buffer) { if (!spidev->rx_buffer) {
spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spidev->rx_buffer) { if (!spidev->rx_buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM; status = -ENOMEM;
goto err_alloc_rx_buf; goto err_alloc_rx_buf;
} }
...@@ -640,10 +640,10 @@ static int spidev_release(struct inode *inode, struct file *filp) ...@@ -640,10 +640,10 @@ static int spidev_release(struct inode *inode, struct file *filp)
spidev = filp->private_data; spidev = filp->private_data;
filp->private_data = NULL; filp->private_data = NULL;
spin_lock_irq(&spidev->spi_lock); mutex_lock(&spidev->spi_lock);
/* ... after we unbound from the underlying device? */ /* ... after we unbound from the underlying device? */
dofree = (spidev->spi == NULL); dofree = (spidev->spi == NULL);
spin_unlock_irq(&spidev->spi_lock); mutex_unlock(&spidev->spi_lock);
/* last close? */ /* last close? */
spidev->users--; spidev->users--;
...@@ -776,7 +776,7 @@ static int spidev_probe(struct spi_device *spi) ...@@ -776,7 +776,7 @@ static int spidev_probe(struct spi_device *spi)
/* Initialize the driver data */ /* Initialize the driver data */
spidev->spi = spi; spidev->spi = spi;
spin_lock_init(&spidev->spi_lock); mutex_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock); mutex_init(&spidev->buf_lock);
INIT_LIST_HEAD(&spidev->device_entry); INIT_LIST_HEAD(&spidev->device_entry);
...@@ -821,9 +821,9 @@ static void spidev_remove(struct spi_device *spi) ...@@ -821,9 +821,9 @@ static void spidev_remove(struct spi_device *spi)
/* prevent new opens */ /* prevent new opens */
mutex_lock(&device_list_lock); mutex_lock(&device_list_lock);
/* make sure ops on existing fds can abort cleanly */ /* make sure ops on existing fds can abort cleanly */
spin_lock_irq(&spidev->spi_lock); mutex_lock(&spidev->spi_lock);
spidev->spi = NULL; spidev->spi = NULL;
spin_unlock_irq(&spidev->spi_lock); mutex_unlock(&spidev->spi_lock);
list_del(&spidev->device_entry); list_del(&spidev->device_entry);
device_destroy(spidev_class, spidev->devt); device_destroy(spidev_class, spidev->devt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment