Skip to content

Commit

Permalink
spi/pl022: move device disable to workqueue thread
Browse files Browse the repository at this point in the history
Moves the disabling of the device and clocks to the same thread in
which the device and clocks are enabled. This avoids SMP issues where
the device can be enabled for a transfer by one thread and then
disabled by the completion of the previous transfer in another thread.

Reviewed-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Chris Blair <chris.blair@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Chris Blair authored and Linus Walleij committed Dec 1, 2011
1 parent 4ca9fb4 commit d4b6af2
Showing 1 changed file with 16 additions and 9 deletions.
25 changes: 16 additions & 9 deletions drivers/spi/spi-pl022.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,6 @@ static void giveback(struct pl022 *pl022)
msg->state = NULL;
if (msg->complete)
msg->complete(msg->context);
/* This message is completed, so let's turn off the clocks & power */
pm_runtime_put(&pl022->adev->dev);
}

/**
Expand Down Expand Up @@ -1509,14 +1507,18 @@ static void pump_messages(struct work_struct *work)
struct pl022 *pl022 =
container_of(work, struct pl022, pump_messages);
unsigned long flags;
bool was_busy = false;

/* Lock queue and check for queue work */
spin_lock_irqsave(&pl022->queue_lock, flags);
if (list_empty(&pl022->queue) || !pl022->running) {
if (pl022->busy)
pm_runtime_put(&pl022->adev->dev);
pl022->busy = false;
spin_unlock_irqrestore(&pl022->queue_lock, flags);
return;
}

/* Make sure we are not already running a message */
if (pl022->cur_msg) {
spin_unlock_irqrestore(&pl022->queue_lock, flags);
Expand All @@ -1527,7 +1529,10 @@ static void pump_messages(struct work_struct *work)
list_entry(pl022->queue.next, struct spi_message, queue);

list_del_init(&pl022->cur_msg->queue);
pl022->busy = true;
if (pl022->busy)
was_busy = true;
else
pl022->busy = true;
spin_unlock_irqrestore(&pl022->queue_lock, flags);

/* Initial message state */
Expand All @@ -1537,12 +1542,14 @@ static void pump_messages(struct work_struct *work)

/* Setup the SPI using the per chip configuration */
pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
/*
* We enable the core voltage and clocks here, then the clocks
* and core will be disabled when giveback() is called in each method
* (poll/interrupt/DMA)
*/
pm_runtime_get_sync(&pl022->adev->dev);
if (!was_busy)
/*
* We enable the core voltage and clocks here, then the clocks
* and core will be disabled when this workqueue is run again
* and there is no more work to be done.
*/
pm_runtime_get_sync(&pl022->adev->dev);

restore_state(pl022);
flush(pl022);

Expand Down

0 comments on commit d4b6af2

Please sign in to comment.