Commit f0125f1a authored by Mark Brown's avatar Mark Brown

spi: Go back to immediate teardown

Commit 412e6037 ("spi: core: avoid waking pump thread from spi_sync
instead run teardown delayed") introduced regressions on some boards,
apparently connected to spi_mem not triggering shutdown properly any
more.  Since we've thus far been unable to figure out exactly where the
breakage is revert the optimisation for now.
Reported-by: default avatarJon Hunter <jonathanh@nvidia.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Cc: kernel@martin.sperl.org
parent 51eea52d
...@@ -1225,7 +1225,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) ...@@ -1225,7 +1225,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
return; return;
} }
/* If another context is idling the device then defer to kthread */ /* If another context is idling the device then defer */
if (ctlr->idling) { if (ctlr->idling) {
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags); spin_unlock_irqrestore(&ctlr->queue_lock, flags);
...@@ -1239,10 +1239,34 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) ...@@ -1239,10 +1239,34 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
return; return;
} }
/* schedule idle teardown with a delay of 1 second */ /* Only do teardown in the thread */
kthread_mod_delayed_work(&ctlr->kworker, if (!in_kthread) {
&ctlr->pump_idle_teardown, kthread_queue_work(&ctlr->kworker,
HZ); &ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return;
}
ctlr->busy = false;
ctlr->idling = true;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
kfree(ctlr->dummy_rx);
ctlr->dummy_rx = NULL;
kfree(ctlr->dummy_tx);
ctlr->dummy_tx = NULL;
if (ctlr->unprepare_transfer_hardware &&
ctlr->unprepare_transfer_hardware(ctlr))
dev_err(&ctlr->dev,
"failed to unprepare transfer hardware\n");
if (ctlr->auto_runtime_pm) {
pm_runtime_mark_last_busy(ctlr->dev.parent);
pm_runtime_put_autosuspend(ctlr->dev.parent);
}
trace_spi_controller_idle(ctlr);
spin_lock_irqsave(&ctlr->queue_lock, flags);
ctlr->idling = false;
spin_unlock_irqrestore(&ctlr->queue_lock, flags); spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return; return;
} }
...@@ -1335,77 +1359,6 @@ static void spi_pump_messages(struct kthread_work *work) ...@@ -1335,77 +1359,6 @@ static void spi_pump_messages(struct kthread_work *work)
__spi_pump_messages(ctlr, true); __spi_pump_messages(ctlr, true);
} }
/**
* spi_pump_idle_teardown - kthread delayed work function which tears down
* the controller settings after some delay
* @work: pointer to kthread work struct contained in the controller struct
*/
static void spi_pump_idle_teardown(struct kthread_work *work)
{
struct spi_controller *ctlr =
container_of(work, struct spi_controller,
pump_idle_teardown.work);
unsigned long flags;
/* Lock queue */
spin_lock_irqsave(&ctlr->queue_lock, flags);
/* Make sure we are not already running a message */
if (ctlr->cur_msg)
goto out;
/* if there is anything in the list then exit */
if (!list_empty(&ctlr->queue))
goto out;
/* if the controller is running then exit */
if (ctlr->running)
goto out;
/* if the controller is busy then exit */
if (ctlr->busy)
goto out;
/* if the controller is idling then exit
* this is actually a bit strange and would indicate that
* this function is scheduled twice, which should not happen
*/
if (ctlr->idling)
goto out;
/* set up the initial states */
ctlr->busy = false;
ctlr->idling = true;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
/* free dummy receive buffers */
kfree(ctlr->dummy_rx);
ctlr->dummy_rx = NULL;
kfree(ctlr->dummy_tx);
ctlr->dummy_tx = NULL;
/* unprepare hardware */
if (ctlr->unprepare_transfer_hardware &&
ctlr->unprepare_transfer_hardware(ctlr))
dev_err(&ctlr->dev,
"failed to unprepare transfer hardware\n");
/* handle pm */
if (ctlr->auto_runtime_pm) {
pm_runtime_mark_last_busy(ctlr->dev.parent);
pm_runtime_put_autosuspend(ctlr->dev.parent);
}
/* mark controller as idle */
trace_spi_controller_idle(ctlr);
/* finally put us from idling into stopped */
spin_lock_irqsave(&ctlr->queue_lock, flags);
ctlr->idling = false;
out:
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
}
static int spi_init_queue(struct spi_controller *ctlr) static int spi_init_queue(struct spi_controller *ctlr)
{ {
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
...@@ -1421,8 +1374,7 @@ static int spi_init_queue(struct spi_controller *ctlr) ...@@ -1421,8 +1374,7 @@ static int spi_init_queue(struct spi_controller *ctlr)
return PTR_ERR(ctlr->kworker_task); return PTR_ERR(ctlr->kworker_task);
} }
kthread_init_work(&ctlr->pump_messages, spi_pump_messages); kthread_init_work(&ctlr->pump_messages, spi_pump_messages);
kthread_init_delayed_work(&ctlr->pump_idle_teardown,
spi_pump_idle_teardown);
/* /*
* Controller config will indicate if this controller should run the * Controller config will indicate if this controller should run the
* message pump with high (realtime) priority to reduce the transfer * message pump with high (realtime) priority to reduce the transfer
...@@ -1494,16 +1446,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr) ...@@ -1494,16 +1446,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
spin_lock_irqsave(&ctlr->queue_lock, flags); spin_lock_irqsave(&ctlr->queue_lock, flags);
ctlr->cur_msg = NULL; ctlr->cur_msg = NULL;
ctlr->cur_msg_prepared = false; ctlr->cur_msg_prepared = false;
/* if there is something queued, then wake the queue */
if (!list_empty(&ctlr->queue))
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
else
/* otherwise schedule delayed teardown */
kthread_mod_delayed_work(&ctlr->kworker,
&ctlr->pump_idle_teardown,
HZ);
spin_unlock_irqrestore(&ctlr->queue_lock, flags); spin_unlock_irqrestore(&ctlr->queue_lock, flags);
trace_spi_message_done(mesg); trace_spi_message_done(mesg);
...@@ -1608,7 +1551,7 @@ static int __spi_queued_transfer(struct spi_device *spi, ...@@ -1608,7 +1551,7 @@ static int __spi_queued_transfer(struct spi_device *spi,
msg->status = -EINPROGRESS; msg->status = -EINPROGRESS;
list_add_tail(&msg->queue, &ctlr->queue); list_add_tail(&msg->queue, &ctlr->queue);
if (need_pump) if (!ctlr->busy && need_pump)
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags); spin_unlock_irqrestore(&ctlr->queue_lock, flags);
...@@ -3783,3 +3726,4 @@ static int __init spi_init(void) ...@@ -3783,3 +3726,4 @@ static int __init spi_init(void)
* include needing to have boardinfo data structures be much more public. * include needing to have boardinfo data structures be much more public.
*/ */
postcore_initcall(spi_init); postcore_initcall(spi_init);
...@@ -334,7 +334,6 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) ...@@ -334,7 +334,6 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @kworker: thread struct for message pump * @kworker: thread struct for message pump
* @kworker_task: pointer to task for message pump kworker thread * @kworker_task: pointer to task for message pump kworker thread
* @pump_messages: work struct for scheduling work to the message pump * @pump_messages: work struct for scheduling work to the message pump
* @pump_idle_teardown: work structure for scheduling a teardown delayed
* @queue_lock: spinlock to syncronise access to message queue * @queue_lock: spinlock to syncronise access to message queue
* @queue: message queue * @queue: message queue
* @idling: the device is entering idle state * @idling: the device is entering idle state
...@@ -533,7 +532,6 @@ struct spi_controller { ...@@ -533,7 +532,6 @@ struct spi_controller {
struct kthread_worker kworker; struct kthread_worker kworker;
struct task_struct *kworker_task; struct task_struct *kworker_task;
struct kthread_work pump_messages; struct kthread_work pump_messages;
struct kthread_delayed_work pump_idle_teardown;
spinlock_t queue_lock; spinlock_t queue_lock;
struct list_head queue; struct list_head queue;
struct spi_message *cur_msg; struct spi_message *cur_msg;
......
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