diff options
author | Chris Blair <chris.blair@stericsson.com> | 2012-02-02 07:59:34 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2012-02-02 13:32:16 -0500 |
commit | 14af60b6fb3b76634278364b697dae2f9f360abf (patch) | |
tree | 7b454608c85bb6823384009a90ebe290431f17cf /drivers/spi/spi-pl022.c | |
parent | 90bbf4fdf2dc64aa7c20a93a9744c56a566baf26 (diff) |
spi/pl022: Add high priority message pump support
This switches the PL022 worker to a kthread in order to get
hold of a mechanism to control the message pump priority. On
low-latency systems elevating the message kthread to realtime
priority give a real sleek response curve. This has been
confirmed by measurements. Realtime priority elevation for
a certain PL022 port can be requested from platform data.
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-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>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi/spi-pl022.c')
-rw-r--r-- | drivers/spi/spi-pl022.c | 77 |
1 files changed, 52 insertions, 25 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 2f9cb43a2398..81847c9a7586 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/spi/spi.h> | 31 | #include <linux/spi/spi.h> |
32 | #include <linux/workqueue.h> | 32 | #include <linux/kthread.h> |
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/clk.h> | 34 | #include <linux/clk.h> |
35 | #include <linux/err.h> | 35 | #include <linux/err.h> |
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/dma-mapping.h> | 41 | #include <linux/dma-mapping.h> |
42 | #include <linux/scatterlist.h> | 42 | #include <linux/scatterlist.h> |
43 | #include <linux/pm_runtime.h> | 43 | #include <linux/pm_runtime.h> |
44 | #include <linux/sched.h> | ||
44 | 45 | ||
45 | /* | 46 | /* |
46 | * This macro is used to define some register default values. | 47 | * This macro is used to define some register default values. |
@@ -330,12 +331,13 @@ struct vendor_data { | |||
330 | * @clk: outgoing clock "SPICLK" for the SPI bus | 331 | * @clk: outgoing clock "SPICLK" for the SPI bus |
331 | * @master: SPI framework hookup | 332 | * @master: SPI framework hookup |
332 | * @master_info: controller-specific data from machine setup | 333 | * @master_info: controller-specific data from machine setup |
333 | * @workqueue: a workqueue on which any spi_message request is queued | 334 | * @kworker: thread struct for message pump |
334 | * @pump_messages: work struct for scheduling work to the workqueue | 335 | * @kworker_task: pointer to task for message pump kworker thread |
336 | * @pump_messages: work struct for scheduling work to the message pump | ||
335 | * @queue_lock: spinlock to syncronise access to message queue | 337 | * @queue_lock: spinlock to syncronise access to message queue |
336 | * @queue: message queue | 338 | * @queue: message queue |
337 | * @busy: workqueue is busy | 339 | * @busy: message pump is busy |
338 | * @running: workqueue is running | 340 | * @running: message pump is running |
339 | * @pump_transfers: Tasklet used in Interrupt Transfer mode | 341 | * @pump_transfers: Tasklet used in Interrupt Transfer mode |
340 | * @cur_msg: Pointer to current spi_message being processed | 342 | * @cur_msg: Pointer to current spi_message being processed |
341 | * @cur_transfer: Pointer to current spi_transfer | 343 | * @cur_transfer: Pointer to current spi_transfer |
@@ -365,9 +367,10 @@ struct pl022 { | |||
365 | struct clk *clk; | 367 | struct clk *clk; |
366 | struct spi_master *master; | 368 | struct spi_master *master; |
367 | struct pl022_ssp_controller *master_info; | 369 | struct pl022_ssp_controller *master_info; |
368 | /* Driver message queue */ | 370 | /* Driver message pump */ |
369 | struct workqueue_struct *workqueue; | 371 | struct kthread_worker kworker; |
370 | struct work_struct pump_messages; | 372 | struct task_struct *kworker_task; |
373 | struct kthread_work pump_messages; | ||
371 | spinlock_t queue_lock; | 374 | spinlock_t queue_lock; |
372 | struct list_head queue; | 375 | struct list_head queue; |
373 | bool busy; | 376 | bool busy; |
@@ -504,7 +507,7 @@ static void giveback(struct pl022 *pl022) | |||
504 | pl022->cur_msg = NULL; | 507 | pl022->cur_msg = NULL; |
505 | pl022->cur_transfer = NULL; | 508 | pl022->cur_transfer = NULL; |
506 | pl022->cur_chip = NULL; | 509 | pl022->cur_chip = NULL; |
507 | queue_work(pl022->workqueue, &pl022->pump_messages); | 510 | queue_kthread_work(&pl022->kworker, &pl022->pump_messages); |
508 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 511 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
509 | 512 | ||
510 | msg->state = NULL; | 513 | msg->state = NULL; |
@@ -1494,8 +1497,8 @@ out: | |||
1494 | } | 1497 | } |
1495 | 1498 | ||
1496 | /** | 1499 | /** |
1497 | * pump_messages - Workqueue function which processes spi message queue | 1500 | * pump_messages - kthread work function which processes spi message queue |
1498 | * @data: pointer to private data of SSP driver | 1501 | * @work: pointer to kthread work struct contained in the pl022 private struct |
1499 | * | 1502 | * |
1500 | * This function checks if there is any spi message in the queue that | 1503 | * This function checks if there is any spi message in the queue that |
1501 | * needs processing and delegate control to appropriate function | 1504 | * needs processing and delegate control to appropriate function |
@@ -1503,7 +1506,7 @@ out: | |||
1503 | * based on the kind of the transfer | 1506 | * based on the kind of the transfer |
1504 | * | 1507 | * |
1505 | */ | 1508 | */ |
1506 | static void pump_messages(struct work_struct *work) | 1509 | static void pump_messages(struct kthread_work *work) |
1507 | { | 1510 | { |
1508 | struct pl022 *pl022 = | 1511 | struct pl022 *pl022 = |
1509 | container_of(work, struct pl022, pump_messages); | 1512 | container_of(work, struct pl022, pump_messages); |
@@ -1556,7 +1559,7 @@ static void pump_messages(struct work_struct *work) | |||
1556 | if (!was_busy) | 1559 | if (!was_busy) |
1557 | /* | 1560 | /* |
1558 | * We enable the core voltage and clocks here, then the clocks | 1561 | * We enable the core voltage and clocks here, then the clocks |
1559 | * and core will be disabled when this workqueue is run again | 1562 | * and core will be disabled when this thread is run again |
1560 | * and there is no more work to be done. | 1563 | * and there is no more work to be done. |
1561 | */ | 1564 | */ |
1562 | pm_runtime_get_sync(&pl022->adev->dev); | 1565 | pm_runtime_get_sync(&pl022->adev->dev); |
@@ -1572,6 +1575,8 @@ static void pump_messages(struct work_struct *work) | |||
1572 | 1575 | ||
1573 | static int __init init_queue(struct pl022 *pl022) | 1576 | static int __init init_queue(struct pl022 *pl022) |
1574 | { | 1577 | { |
1578 | struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; | ||
1579 | |||
1575 | INIT_LIST_HEAD(&pl022->queue); | 1580 | INIT_LIST_HEAD(&pl022->queue); |
1576 | spin_lock_init(&pl022->queue_lock); | 1581 | spin_lock_init(&pl022->queue_lock); |
1577 | 1582 | ||
@@ -1581,11 +1586,29 @@ static int __init init_queue(struct pl022 *pl022) | |||
1581 | tasklet_init(&pl022->pump_transfers, pump_transfers, | 1586 | tasklet_init(&pl022->pump_transfers, pump_transfers, |
1582 | (unsigned long)pl022); | 1587 | (unsigned long)pl022); |
1583 | 1588 | ||
1584 | INIT_WORK(&pl022->pump_messages, pump_messages); | 1589 | init_kthread_worker(&pl022->kworker); |
1585 | pl022->workqueue = create_singlethread_workqueue( | 1590 | pl022->kworker_task = kthread_run(kthread_worker_fn, |
1591 | &pl022->kworker, | ||
1586 | dev_name(pl022->master->dev.parent)); | 1592 | dev_name(pl022->master->dev.parent)); |
1587 | if (pl022->workqueue == NULL) | 1593 | if (IS_ERR(pl022->kworker_task)) { |
1588 | return -EBUSY; | 1594 | dev_err(&pl022->adev->dev, |
1595 | "failed to create message pump task\n"); | ||
1596 | return -ENOMEM; | ||
1597 | } | ||
1598 | init_kthread_work(&pl022->pump_messages, pump_messages); | ||
1599 | |||
1600 | /* | ||
1601 | * Board config will indicate if this controller should run the | ||
1602 | * message pump with high (realtime) priority to reduce the transfer | ||
1603 | * latency on the bus by minimising the delay between a transfer | ||
1604 | * request and the scheduling of the message pump thread. Without this | ||
1605 | * setting the message pump thread will remain at default priority. | ||
1606 | */ | ||
1607 | if (pl022->master_info->rt) { | ||
1608 | dev_info(&pl022->adev->dev, | ||
1609 | "will run message pump with realtime priority\n"); | ||
1610 | sched_setscheduler(pl022->kworker_task, SCHED_FIFO, ¶m); | ||
1611 | } | ||
1589 | 1612 | ||
1590 | return 0; | 1613 | return 0; |
1591 | } | 1614 | } |
@@ -1608,7 +1631,7 @@ static int start_queue(struct pl022 *pl022) | |||
1608 | pl022->next_msg_cs_active = false; | 1631 | pl022->next_msg_cs_active = false; |
1609 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 1632 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
1610 | 1633 | ||
1611 | queue_work(pl022->workqueue, &pl022->pump_messages); | 1634 | queue_kthread_work(&pl022->kworker, &pl022->pump_messages); |
1612 | 1635 | ||
1613 | return 0; | 1636 | return 0; |
1614 | } | 1637 | } |
@@ -1646,16 +1669,20 @@ static int destroy_queue(struct pl022 *pl022) | |||
1646 | int status; | 1669 | int status; |
1647 | 1670 | ||
1648 | status = stop_queue(pl022); | 1671 | status = stop_queue(pl022); |
1649 | /* we are unloading the module or failing to load (only two calls | 1672 | |
1673 | /* | ||
1674 | * We are unloading the module or failing to load (only two calls | ||
1650 | * to this routine), and neither call can handle a return value. | 1675 | * to this routine), and neither call can handle a return value. |
1651 | * However, destroy_workqueue calls flush_workqueue, and that will | 1676 | * However, flush_kthread_worker will block until all work is done. |
1652 | * block until all work is done. If the reason that stop_queue | 1677 | * If the reason that stop_queue timed out is that the work will never |
1653 | * timed out is that the work will never finish, then it does no | 1678 | * finish, then it does no good to call flush/stop thread, so |
1654 | * good to call destroy_workqueue, so return anyway. */ | 1679 | * return anyway. |
1680 | */ | ||
1655 | if (status != 0) | 1681 | if (status != 0) |
1656 | return status; | 1682 | return status; |
1657 | 1683 | ||
1658 | destroy_workqueue(pl022->workqueue); | 1684 | flush_kthread_worker(&pl022->kworker); |
1685 | kthread_stop(pl022->kworker_task); | ||
1659 | 1686 | ||
1660 | return 0; | 1687 | return 0; |
1661 | } | 1688 | } |
@@ -1802,7 +1829,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg) | |||
1802 | 1829 | ||
1803 | list_add_tail(&msg->queue, &pl022->queue); | 1830 | list_add_tail(&msg->queue, &pl022->queue); |
1804 | if (pl022->running && !pl022->busy) | 1831 | if (pl022->running && !pl022->busy) |
1805 | queue_work(pl022->workqueue, &pl022->pump_messages); | 1832 | queue_kthread_work(&pl022->kworker, &pl022->pump_messages); |
1806 | 1833 | ||
1807 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 1834 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
1808 | return 0; | 1835 | return 0; |