aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/pending-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/pending-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch')
-rw-r--r--target/linux/generic/pending-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch184
1 files changed, 0 insertions, 184 deletions
diff --git a/target/linux/generic/pending-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch b/target/linux/generic/pending-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch
deleted file mode 100644
index b74b4cb93b..0000000000
--- a/target/linux/generic/pending-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch
+++ /dev/null
@@ -1,184 +0,0 @@
-From: Mark Brown <broonie@kernel.org>
-Date: Tue, 9 Dec 2014 21:38:05 +0000
-Subject: [PATCH] spi: Pump transfers inside calling context for spi_sync()
-
-If we are using the standard SPI message pump (which all drivers should be
-transitioning over to) then special case the message enqueue and instead of
-starting the worker thread to push messages to the hardware do so in the
-context of the caller if the controller is idle. This avoids a context
-switch in the common case where the controller has a single user in a
-single thread, for short PIO transfers there may be no need to context
-switch away from the calling context to complete the transfer.
-
-The code is a bit more complex than is desirable in part due to the need
-to handle drivers not using the standard queue and in part due to handling
-the various combinations of bus locking and asynchronous submission in
-interrupt context.
-
-It is still suboptimal since it will still wake the message pump for each
-transfer in order to schedule idling of the hardware and if multiple
-contexts are using the controller simultaneously a caller may end up
-pumping a message for some random other thread rather than for itself,
-and if the thread ends up deferring due to another context idling the
-hardware then it will just busy wait. It can, however, have the benefit
-of aggregating power up and down of the hardware when a caller performs
-a series of transfers back to back without any need for the use of
-spi_async().
-
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
-
---- a/drivers/spi/spi.c
-+++ b/drivers/spi/spi.c
-@@ -882,6 +882,9 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_t
- * needs processing and if so call out to the driver to initialize hardware
- * and transfer each message.
- *
-+ * Note that it is called both from the kthread itself and also from
-+ * inside spi_sync(); the queue extraction handling at the top of the
-+ * function should deal with this safely.
- */
- static void spi_pump_messages(struct kthread_work *work)
- {
-@@ -900,6 +903,13 @@ static void spi_pump_messages(struct kth
- return;
- }
-
-+ /* If another context is idling the device then defer */
-+ if (master->idling) {
-+ queue_kthread_work(&master->kworker, &master->pump_messages);
-+ spin_unlock_irqrestore(&master->queue_lock, flags);
-+ return;
-+ }
-+
- /* Check if the queue is idle */
- if (list_empty(&master->queue) || !master->running) {
- if (!master->busy) {
-@@ -907,7 +917,9 @@ static void spi_pump_messages(struct kth
- return;
- }
- master->busy = false;
-+ master->idling = true;
- spin_unlock_irqrestore(&master->queue_lock, flags);
-+
- kfree(master->dummy_rx);
- master->dummy_rx = NULL;
- kfree(master->dummy_tx);
-@@ -921,6 +933,10 @@ static void spi_pump_messages(struct kth
- pm_runtime_put_autosuspend(master->dev.parent);
- }
- trace_spi_master_idle(master);
-+
-+ spin_lock_irqsave(&master->queue_lock, flags);
-+ master->idling = false;
-+ spin_unlock_irqrestore(&master->queue_lock, flags);
- return;
- }
-
-@@ -1166,12 +1182,9 @@ static int spi_destroy_queue(struct spi_
- return 0;
- }
-
--/**
-- * spi_queued_transfer - transfer function for queued transfers
-- * @spi: spi device which is requesting transfer
-- * @msg: spi message which is to handled is queued to driver queue
-- */
--static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
-+static int __spi_queued_transfer(struct spi_device *spi,
-+ struct spi_message *msg,
-+ bool need_pump)
- {
- struct spi_master *master = spi->master;
- unsigned long flags;
-@@ -1186,13 +1199,23 @@ static int spi_queued_transfer(struct sp
- msg->status = -EINPROGRESS;
-
- list_add_tail(&msg->queue, &master->queue);
-- if (!master->busy)
-+ if (!master->busy && need_pump)
- queue_kthread_work(&master->kworker, &master->pump_messages);
-
- spin_unlock_irqrestore(&master->queue_lock, flags);
- return 0;
- }
-
-+/**
-+ * spi_queued_transfer - transfer function for queued transfers
-+ * @spi: spi device which is requesting transfer
-+ * @msg: spi message which is to handled is queued to driver queue
-+ */
-+static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
-+{
-+ return __spi_queued_transfer(spi, msg, true);
-+}
-+
- static int spi_master_initialize_queue(struct spi_master *master)
- {
- int ret;
-@@ -2104,19 +2127,46 @@ static int __spi_sync(struct spi_device
- DECLARE_COMPLETION_ONSTACK(done);
- int status;
- struct spi_master *master = spi->master;
-+ unsigned long flags;
-+
-+ status = __spi_validate(spi, message);
-+ if (status != 0)
-+ return status;
-
- message->complete = spi_complete;
- message->context = &done;
-+ message->spi = spi;
-
- if (!bus_locked)
- mutex_lock(&master->bus_lock_mutex);
-
-- status = spi_async_locked(spi, message);
-+ /* If we're not using the legacy transfer method then we will
-+ * try to transfer in the calling context so special case.
-+ * This code would be less tricky if we could remove the
-+ * support for driver implemented message queues.
-+ */
-+ if (master->transfer == spi_queued_transfer) {
-+ spin_lock_irqsave(&master->bus_lock_spinlock, flags);
-+
-+ trace_spi_message_submit(message);
-+
-+ status = __spi_queued_transfer(spi, message, false);
-+
-+ spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
-+ } else {
-+ status = spi_async_locked(spi, message);
-+ }
-
- if (!bus_locked)
- mutex_unlock(&master->bus_lock_mutex);
-
- if (status == 0) {
-+ /* Push out the messages in the calling context if we
-+ * can.
-+ */
-+ if (master->transfer == spi_queued_transfer)
-+ spi_pump_messages(&master->pump_messages);
-+
- wait_for_completion(&done);
- status = message->status;
- }
---- a/include/linux/spi/spi.h
-+++ b/include/linux/spi/spi.h
-@@ -260,6 +260,7 @@ static inline void spi_unregister_driver
- * @pump_messages: work struct for scheduling work to the message pump
- * @queue_lock: spinlock to syncronise access to message queue
- * @queue: message queue
-+ * @idling: the device is entering idle state
- * @cur_msg: the currently in-flight message
- * @cur_msg_prepared: spi_prepare_message was called for the currently
- * in-flight message
-@@ -425,6 +426,7 @@ struct spi_master {
- spinlock_t queue_lock;
- struct list_head queue;
- struct spi_message *cur_msg;
-+ bool idling;
- bool busy;
- bool running;
- bool rt;