Merge remote-tracking branch 'spi/fix/locking' into spi-next
This commit is contained in:
commit
dec34e8b67
@ -1069,7 +1069,6 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
|
|||||||
* __spi_pump_messages - function which processes spi message queue
|
* __spi_pump_messages - function which processes spi message queue
|
||||||
* @master: master to process queue for
|
* @master: master to process queue for
|
||||||
* @in_kthread: true if we are in the context of the message pump thread
|
* @in_kthread: true if we are in the context of the message pump thread
|
||||||
* @bus_locked: true if the bus mutex is held when calling this function
|
|
||||||
*
|
*
|
||||||
* This function checks if there is any spi message in the queue that
|
* This function checks if there is any spi message in the queue that
|
||||||
* needs processing and if so call out to the driver to initialize hardware
|
* needs processing and if so call out to the driver to initialize hardware
|
||||||
@ -1079,8 +1078,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
|
|||||||
* inside spi_sync(); the queue extraction handling at the top of the
|
* inside spi_sync(); the queue extraction handling at the top of the
|
||||||
* function should deal with this safely.
|
* function should deal with this safely.
|
||||||
*/
|
*/
|
||||||
static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
|
static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
|
||||||
bool bus_locked)
|
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
bool was_busy = false;
|
bool was_busy = false;
|
||||||
@ -1152,6 +1150,8 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
|
|||||||
master->busy = true;
|
master->busy = true;
|
||||||
spin_unlock_irqrestore(&master->queue_lock, flags);
|
spin_unlock_irqrestore(&master->queue_lock, flags);
|
||||||
|
|
||||||
|
mutex_lock(&master->io_mutex);
|
||||||
|
|
||||||
if (!was_busy && master->auto_runtime_pm) {
|
if (!was_busy && master->auto_runtime_pm) {
|
||||||
ret = pm_runtime_get_sync(master->dev.parent);
|
ret = pm_runtime_get_sync(master->dev.parent);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -1176,9 +1176,6 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bus_locked)
|
|
||||||
mutex_lock(&master->bus_lock_mutex);
|
|
||||||
|
|
||||||
trace_spi_message_start(master->cur_msg);
|
trace_spi_message_start(master->cur_msg);
|
||||||
|
|
||||||
if (master->prepare_message) {
|
if (master->prepare_message) {
|
||||||
@ -1208,8 +1205,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (!bus_locked)
|
mutex_unlock(&master->io_mutex);
|
||||||
mutex_unlock(&master->bus_lock_mutex);
|
|
||||||
|
|
||||||
/* Prod the scheduler in case transfer_one() was busy waiting */
|
/* Prod the scheduler in case transfer_one() was busy waiting */
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@ -1225,7 +1221,7 @@ static void spi_pump_messages(struct kthread_work *work)
|
|||||||
struct spi_master *master =
|
struct spi_master *master =
|
||||||
container_of(work, struct spi_master, pump_messages);
|
container_of(work, struct spi_master, pump_messages);
|
||||||
|
|
||||||
__spi_pump_messages(master, true, master->bus_lock_flag);
|
__spi_pump_messages(master, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spi_init_queue(struct spi_master *master)
|
static int spi_init_queue(struct spi_master *master)
|
||||||
@ -1887,6 +1883,7 @@ int spi_register_master(struct spi_master *master)
|
|||||||
spin_lock_init(&master->queue_lock);
|
spin_lock_init(&master->queue_lock);
|
||||||
spin_lock_init(&master->bus_lock_spinlock);
|
spin_lock_init(&master->bus_lock_spinlock);
|
||||||
mutex_init(&master->bus_lock_mutex);
|
mutex_init(&master->bus_lock_mutex);
|
||||||
|
mutex_init(&master->io_mutex);
|
||||||
master->bus_lock_flag = 0;
|
master->bus_lock_flag = 0;
|
||||||
init_completion(&master->xfer_completion);
|
init_completion(&master->xfer_completion);
|
||||||
if (!master->max_dma_len)
|
if (!master->max_dma_len)
|
||||||
@ -2767,6 +2764,7 @@ int spi_flash_read(struct spi_device *spi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&master->bus_lock_mutex);
|
mutex_lock(&master->bus_lock_mutex);
|
||||||
|
mutex_lock(&master->io_mutex);
|
||||||
if (master->dma_rx) {
|
if (master->dma_rx) {
|
||||||
rx_dev = master->dma_rx->device->dev;
|
rx_dev = master->dma_rx->device->dev;
|
||||||
ret = spi_map_buf(master, rx_dev, &msg->rx_sg,
|
ret = spi_map_buf(master, rx_dev, &msg->rx_sg,
|
||||||
@ -2779,6 +2777,7 @@ int spi_flash_read(struct spi_device *spi,
|
|||||||
if (msg->cur_msg_mapped)
|
if (msg->cur_msg_mapped)
|
||||||
spi_unmap_buf(master, rx_dev, &msg->rx_sg,
|
spi_unmap_buf(master, rx_dev, &msg->rx_sg,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
|
mutex_unlock(&master->io_mutex);
|
||||||
mutex_unlock(&master->bus_lock_mutex);
|
mutex_unlock(&master->bus_lock_mutex);
|
||||||
|
|
||||||
if (master->auto_runtime_pm)
|
if (master->auto_runtime_pm)
|
||||||
@ -2800,8 +2799,7 @@ static void spi_complete(void *arg)
|
|||||||
complete(arg);
|
complete(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __spi_sync(struct spi_device *spi, struct spi_message *message,
|
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
|
||||||
int bus_locked)
|
|
||||||
{
|
{
|
||||||
DECLARE_COMPLETION_ONSTACK(done);
|
DECLARE_COMPLETION_ONSTACK(done);
|
||||||
int status;
|
int status;
|
||||||
@ -2819,9 +2817,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
|
|||||||
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);
|
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);
|
||||||
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
|
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
|
||||||
|
|
||||||
if (!bus_locked)
|
|
||||||
mutex_lock(&master->bus_lock_mutex);
|
|
||||||
|
|
||||||
/* If we're not using the legacy transfer method then we will
|
/* If we're not using the legacy transfer method then we will
|
||||||
* try to transfer in the calling context so special case.
|
* try to transfer in the calling context so special case.
|
||||||
* This code would be less tricky if we could remove the
|
* This code would be less tricky if we could remove the
|
||||||
@ -2839,9 +2834,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
|
|||||||
status = spi_async_locked(spi, message);
|
status = spi_async_locked(spi, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bus_locked)
|
|
||||||
mutex_unlock(&master->bus_lock_mutex);
|
|
||||||
|
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
/* Push out the messages in the calling context if we
|
/* Push out the messages in the calling context if we
|
||||||
* can.
|
* can.
|
||||||
@ -2851,7 +2843,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
|
|||||||
spi_sync_immediate);
|
spi_sync_immediate);
|
||||||
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
|
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
|
||||||
spi_sync_immediate);
|
spi_sync_immediate);
|
||||||
__spi_pump_messages(master, false, bus_locked);
|
__spi_pump_messages(master, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_completion(&done);
|
wait_for_completion(&done);
|
||||||
@ -2884,7 +2876,13 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
|
|||||||
*/
|
*/
|
||||||
int spi_sync(struct spi_device *spi, struct spi_message *message)
|
int spi_sync(struct spi_device *spi, struct spi_message *message)
|
||||||
{
|
{
|
||||||
return __spi_sync(spi, message, spi->master->bus_lock_flag);
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&spi->master->bus_lock_mutex);
|
||||||
|
ret = __spi_sync(spi, message);
|
||||||
|
mutex_unlock(&spi->master->bus_lock_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_sync);
|
EXPORT_SYMBOL_GPL(spi_sync);
|
||||||
|
|
||||||
@ -2906,7 +2904,7 @@ EXPORT_SYMBOL_GPL(spi_sync);
|
|||||||
*/
|
*/
|
||||||
int spi_sync_locked(struct spi_device *spi, struct spi_message *message)
|
int spi_sync_locked(struct spi_device *spi, struct spi_message *message)
|
||||||
{
|
{
|
||||||
return __spi_sync(spi, message, 1);
|
return __spi_sync(spi, message);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_sync_locked);
|
EXPORT_SYMBOL_GPL(spi_sync_locked);
|
||||||
|
|
||||||
|
@ -312,8 +312,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
|||||||
* @flags: other constraints relevant to this driver
|
* @flags: other constraints relevant to this driver
|
||||||
* @max_transfer_size: function that returns the max transfer size for
|
* @max_transfer_size: function that returns the max transfer size for
|
||||||
* a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
|
* a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
|
||||||
|
* @io_mutex: mutex for physical bus access
|
||||||
* @bus_lock_spinlock: spinlock for SPI bus locking
|
* @bus_lock_spinlock: spinlock for SPI bus locking
|
||||||
* @bus_lock_mutex: mutex for SPI bus locking
|
* @bus_lock_mutex: mutex for exclusion of multiple callers
|
||||||
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
|
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
|
||||||
* @setup: updates the device mode and clocking records used by a
|
* @setup: updates the device mode and clocking records used by a
|
||||||
* device's SPI controller; protocol code may call this. This
|
* device's SPI controller; protocol code may call this. This
|
||||||
@ -446,6 +447,9 @@ struct spi_master {
|
|||||||
*/
|
*/
|
||||||
size_t (*max_transfer_size)(struct spi_device *spi);
|
size_t (*max_transfer_size)(struct spi_device *spi);
|
||||||
|
|
||||||
|
/* I/O mutex */
|
||||||
|
struct mutex io_mutex;
|
||||||
|
|
||||||
/* lock and mutex for SPI bus locking */
|
/* lock and mutex for SPI bus locking */
|
||||||
spinlock_t bus_lock_spinlock;
|
spinlock_t bus_lock_spinlock;
|
||||||
struct mutex bus_lock_mutex;
|
struct mutex bus_lock_mutex;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user