123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 |
- commit ffbbdd21329f3e15eeca6df2d4bc11c04d9d91c0
- Author: Linus Walleij <linus.walleij@linaro.org>
- Date: Wed Feb 22 10:05:38 2012 +0100
- spi: create a message queueing infrastructure
-
- This rips the message queue in the PL022 driver out and pushes
- it into (optional) common infrastructure. Drivers that want to
- use the message pumping thread will need to define the new
- per-messags transfer methods and leave the deprecated transfer()
- method as NULL.
-
- Most of the design is described in the documentation changes that
- are included in this patch.
-
- Since there is a queue that need to be stopped when the system
- is suspending/resuming, two new calls are implemented for the
- device drivers to call in their suspend()/resume() functions:
- spi_master_suspend() and spi_master_resume().
-
- ChangeLog v1->v2:
- - Remove Kconfig entry and do not make the queue support optional
- at all, instead be more agressive and have it as part of the
- compulsory infrastructure.
- - If the .transfer() method is implemented, delete print a small
- deprecation notice and do not start the transfer pump.
- - Fix a bitrotted comment.
- ChangeLog v2->v3:
- - Fix up a problematic sequence courtesy of Chris Blair.
- - Stop rather than destroy the queue on suspend() courtesy of
- Chris Blair.
-
- Signed-off-by: Chris Blair <chris.blair@stericsson.com>
- Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
- Tested-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
- Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
- Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
- [Florian: dropped the changes on drivers/spi/spi-pl022.c, removed
- the dev_info() about unqueued drivers still using the master function]
- --- a/Documentation/spi/spi-summary
- +++ b/Documentation/spi/spi-summary
- @@ -1,7 +1,7 @@
- Overview of Linux kernel SPI support
- ====================================
-
- -21-May-2007
- +02-Feb-2012
-
- What is SPI?
- ------------
- @@ -483,9 +483,9 @@ also initialize its own internal state.
- and those methods.)
-
- After you initialize the spi_master, then use spi_register_master() to
- -publish it to the rest of the system. At that time, device nodes for
- -the controller and any predeclared spi devices will be made available,
- -and the driver model core will take care of binding them to drivers.
- +publish it to the rest of the system. At that time, device nodes for the
- +controller and any predeclared spi devices will be made available, and
- +the driver model core will take care of binding them to drivers.
-
- If you need to remove your SPI controller driver, spi_unregister_master()
- will reverse the effect of spi_register_master().
- @@ -521,21 +521,53 @@ SPI MASTER METHODS
- ** When you code setup(), ASSUME that the controller
- ** is actively processing transfers for another device.
-
- - master->transfer(struct spi_device *spi, struct spi_message *message)
- - This must not sleep. Its responsibility is arrange that the
- - transfer happens and its complete() callback is issued. The two
- - will normally happen later, after other transfers complete, and
- - if the controller is idle it will need to be kickstarted.
- -
- master->cleanup(struct spi_device *spi)
- Your controller driver may use spi_device.controller_state to hold
- state it dynamically associates with that device. If you do that,
- be sure to provide the cleanup() method to free that state.
-
- + master->prepare_transfer_hardware(struct spi_master *master)
- + This will be called by the queue mechanism to signal to the driver
- + that a message is coming in soon, so the subsystem requests the
- + driver to prepare the transfer hardware by issuing this call.
- + This may sleep.
- +
- + master->unprepare_transfer_hardware(struct spi_master *master)
- + This will be called by the queue mechanism to signal to the driver
- + that there are no more messages pending in the queue and it may
- + relax the hardware (e.g. by power management calls). This may sleep.
- +
- + master->transfer_one_message(struct spi_master *master,
- + struct spi_message *mesg)
- + The subsystem calls the driver to transfer a single message while
- + queuing transfers that arrive in the meantime. When the driver is
- + finished with this message, it must call
- + spi_finalize_current_message() so the subsystem can issue the next
- + transfer. This may sleep.
- +
- + DEPRECATED METHODS
- +
- + master->transfer(struct spi_device *spi, struct spi_message *message)
- + This must not sleep. Its responsibility is arrange that the
- + transfer happens and its complete() callback is issued. The two
- + will normally happen later, after other transfers complete, and
- + if the controller is idle it will need to be kickstarted. This
- + method is not used on queued controllers and must be NULL if
- + transfer_one_message() and (un)prepare_transfer_hardware() are
- + implemented.
- +
-
- SPI MESSAGE QUEUE
-
- -The bulk of the driver will be managing the I/O queue fed by transfer().
- +If you are happy with the standard queueing mechanism provided by the
- +SPI subsystem, just implement the queued methods specified above. Using
- +the message queue has the upside of centralizing a lot of code and
- +providing pure process-context execution of methods. The message queue
- +can also be elevated to realtime priority on high-priority SPI traffic.
- +
- +Unless the queueing mechanism in the SPI subsystem is selected, the bulk
- +of the driver will be managing the I/O queue fed by the now deprecated
- +function transfer().
-
- That queue could be purely conceptual. For example, a driver used only
- for low-frequency sensor access might be fine using synchronous PIO.
- @@ -561,4 +593,6 @@ Stephen Street
- Mark Underwood
- Andrew Victor
- Vitaly Wool
- -
- +Grant Likely
- +Mark Brown
- +Linus Walleij
- --- a/drivers/spi/spi.c
- +++ b/drivers/spi/spi.c
- @@ -30,6 +30,9 @@
- #include <linux/of_spi.h>
- #include <linux/pm_runtime.h>
- #include <linux/export.h>
- +#include <linux/sched.h>
- +#include <linux/delay.h>
- +#include <linux/kthread.h>
-
- static void spidev_release(struct device *dev)
- {
- @@ -507,6 +510,293 @@ spi_register_board_info(struct spi_board
-
- /*-------------------------------------------------------------------------*/
-
- +/**
- + * spi_pump_messages - kthread work function which processes spi message queue
- + * @work: pointer to kthread work struct contained in the master struct
- + *
- + * 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
- + * and transfer each message.
- + *
- + */
- +static void spi_pump_messages(struct kthread_work *work)
- +{
- + struct spi_master *master =
- + container_of(work, struct spi_master, pump_messages);
- + unsigned long flags;
- + bool was_busy = false;
- + int ret;
- +
- + /* Lock queue and check for queue work */
- + spin_lock_irqsave(&master->queue_lock, flags);
- + if (list_empty(&master->queue) || !master->running) {
- + if (master->busy) {
- + ret = master->unprepare_transfer_hardware(master);
- + if (ret) {
- + dev_err(&master->dev,
- + "failed to unprepare transfer hardware\n");
- + return;
- + }
- + }
- + master->busy = false;
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- + return;
- + }
- +
- + /* Make sure we are not already running a message */
- + if (master->cur_msg) {
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- + return;
- + }
- + /* Extract head of queue */
- + master->cur_msg =
- + list_entry(master->queue.next, struct spi_message, queue);
- +
- + list_del_init(&master->cur_msg->queue);
- + if (master->busy)
- + was_busy = true;
- + else
- + master->busy = true;
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- +
- + if (!was_busy) {
- + ret = master->prepare_transfer_hardware(master);
- + if (ret) {
- + dev_err(&master->dev,
- + "failed to prepare transfer hardware\n");
- + return;
- + }
- + }
- +
- + ret = master->transfer_one_message(master, master->cur_msg);
- + if (ret) {
- + dev_err(&master->dev,
- + "failed to transfer one message from queue\n");
- + return;
- + }
- +}
- +
- +static int spi_init_queue(struct spi_master *master)
- +{
- + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
- +
- + INIT_LIST_HEAD(&master->queue);
- + spin_lock_init(&master->queue_lock);
- +
- + master->running = false;
- + master->busy = false;
- +
- + init_kthread_worker(&master->kworker);
- + master->kworker_task = kthread_run(kthread_worker_fn,
- + &master->kworker,
- + dev_name(&master->dev));
- + if (IS_ERR(master->kworker_task)) {
- + dev_err(&master->dev, "failed to create message pump task\n");
- + return -ENOMEM;
- + }
- + init_kthread_work(&master->pump_messages, spi_pump_messages);
- +
- + /*
- + * Master config will indicate if this controller should run the
- + * message pump with high (realtime) priority to reduce the transfer
- + * latency on the bus by minimising the delay between a transfer
- + * request and the scheduling of the message pump thread. Without this
- + * setting the message pump thread will remain at default priority.
- + */
- + if (master->rt) {
- + dev_info(&master->dev,
- + "will run message pump with realtime priority\n");
- + sched_setscheduler(master->kworker_task, SCHED_FIFO, ¶m);
- + }
- +
- + return 0;
- +}
- +
- +/**
- + * spi_get_next_queued_message() - called by driver to check for queued
- + * messages
- + * @master: the master to check for queued messages
- + *
- + * If there are more messages in the queue, the next message is returned from
- + * this call.
- + */
- +struct spi_message *spi_get_next_queued_message(struct spi_master *master)
- +{
- + struct spi_message *next;
- + unsigned long flags;
- +
- + /* get a pointer to the next message, if any */
- + spin_lock_irqsave(&master->queue_lock, flags);
- + if (list_empty(&master->queue))
- + next = NULL;
- + else
- + next = list_entry(master->queue.next,
- + struct spi_message, queue);
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- +
- + return next;
- +}
- +EXPORT_SYMBOL_GPL(spi_get_next_queued_message);
- +
- +/**
- + * spi_finalize_current_message() - the current message is complete
- + * @master: the master to return the message to
- + *
- + * Called by the driver to notify the core that the message in the front of the
- + * queue is complete and can be removed from the queue.
- + */
- +void spi_finalize_current_message(struct spi_master *master)
- +{
- + struct spi_message *mesg;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&master->queue_lock, flags);
- + mesg = master->cur_msg;
- + master->cur_msg = NULL;
- +
- + queue_kthread_work(&master->kworker, &master->pump_messages);
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- +
- + mesg->state = NULL;
- + if (mesg->complete)
- + mesg->complete(mesg->context);
- +}
- +EXPORT_SYMBOL_GPL(spi_finalize_current_message);
- +
- +static int spi_start_queue(struct spi_master *master)
- +{
- + unsigned long flags;
- +
- + spin_lock_irqsave(&master->queue_lock, flags);
- +
- + if (master->running || master->busy) {
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- + return -EBUSY;
- + }
- +
- + master->running = true;
- + master->cur_msg = NULL;
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- +
- + queue_kthread_work(&master->kworker, &master->pump_messages);
- +
- + return 0;
- +}
- +
- +static int spi_stop_queue(struct spi_master *master)
- +{
- + unsigned long flags;
- + unsigned limit = 500;
- + int ret = 0;
- +
- + spin_lock_irqsave(&master->queue_lock, flags);
- +
- + /*
- + * This is a bit lame, but is optimized for the common execution path.
- + * A wait_queue on the master->busy could be used, but then the common
- + * execution path (pump_messages) would be required to call wake_up or
- + * friends on every SPI message. Do this instead.
- + */
- + while ((!list_empty(&master->queue) || master->busy) && limit--) {
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- + msleep(10);
- + spin_lock_irqsave(&master->queue_lock, flags);
- + }
- +
- + if (!list_empty(&master->queue) || master->busy)
- + ret = -EBUSY;
- + else
- + master->running = false;
- +
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- +
- + if (ret) {
- + dev_warn(&master->dev,
- + "could not stop message queue\n");
- + return ret;
- + }
- + return ret;
- +}
- +
- +static int spi_destroy_queue(struct spi_master *master)
- +{
- + int ret;
- +
- + ret = spi_stop_queue(master);
- +
- + /*
- + * flush_kthread_worker will block until all work is done.
- + * If the reason that stop_queue timed out is that the work will never
- + * finish, then it does no good to call flush/stop thread, so
- + * return anyway.
- + */
- + if (ret) {
- + dev_err(&master->dev, "problem destroying queue\n");
- + return ret;
- + }
- +
- + flush_kthread_worker(&master->kworker);
- + kthread_stop(master->kworker_task);
- +
- + 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)
- +{
- + struct spi_master *master = spi->master;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&master->queue_lock, flags);
- +
- + if (!master->running) {
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- + return -ESHUTDOWN;
- + }
- + msg->actual_length = 0;
- + msg->status = -EINPROGRESS;
- +
- + list_add_tail(&msg->queue, &master->queue);
- + if (master->running && !master->busy)
- + queue_kthread_work(&master->kworker, &master->pump_messages);
- +
- + spin_unlock_irqrestore(&master->queue_lock, flags);
- + return 0;
- +}
- +
- +static int spi_master_initialize_queue(struct spi_master *master)
- +{
- + int ret;
- +
- + master->queued = true;
- + master->transfer = spi_queued_transfer;
- +
- + /* Initialize and start queue */
- + ret = spi_init_queue(master);
- + if (ret) {
- + dev_err(&master->dev, "problem initializing queue\n");
- + goto err_init_queue;
- + }
- + ret = spi_start_queue(master);
- + if (ret) {
- + dev_err(&master->dev, "problem starting queue\n");
- + goto err_start_queue;
- + }
- +
- + return 0;
- +
- +err_start_queue:
- +err_init_queue:
- + spi_destroy_queue(master);
- + return ret;
- +}
- +
- +/*-------------------------------------------------------------------------*/
- +
- static void spi_master_release(struct device *dev)
- {
- struct spi_master *master;
- @@ -522,6 +812,7 @@ static struct class spi_master_class = {
- };
-
-
- +
- /**
- * spi_alloc_master - allocate SPI master controller
- * @dev: the controller, possibly using the platform_bus
- @@ -621,6 +912,15 @@ int spi_register_master(struct spi_maste
- dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
- dynamic ? " (dynamic)" : "");
-
- + /* If we're using a queued driver, start the queue */
- + if (!master->transfer) {
- + status = spi_master_initialize_queue(master);
- + if (status) {
- + device_unregister(&master->dev);
- + goto done;
- + }
- + }
- +
- mutex_lock(&board_lock);
- list_add_tail(&master->list, &spi_master_list);
- list_for_each_entry(bi, &board_list, list)
- @@ -636,7 +936,6 @@ done:
- }
- EXPORT_SYMBOL_GPL(spi_register_master);
-
- -
- static int __unregister(struct device *dev, void *null)
- {
- spi_unregister_device(to_spi_device(dev));
- @@ -657,6 +956,11 @@ void spi_unregister_master(struct spi_ma
- {
- int dummy;
-
- + if (master->queued) {
- + if (spi_destroy_queue(master))
- + dev_err(&master->dev, "queue remove failed\n");
- + }
- +
- mutex_lock(&board_lock);
- list_del(&master->list);
- mutex_unlock(&board_lock);
- @@ -666,6 +970,37 @@ void spi_unregister_master(struct spi_ma
- }
- EXPORT_SYMBOL_GPL(spi_unregister_master);
-
- +int spi_master_suspend(struct spi_master *master)
- +{
- + int ret;
- +
- + /* Basically no-ops for non-queued masters */
- + if (!master->queued)
- + return 0;
- +
- + ret = spi_stop_queue(master);
- + if (ret)
- + dev_err(&master->dev, "queue stop failed\n");
- +
- + return ret;
- +}
- +EXPORT_SYMBOL_GPL(spi_master_suspend);
- +
- +int spi_master_resume(struct spi_master *master)
- +{
- + int ret;
- +
- + if (!master->queued)
- + return 0;
- +
- + ret = spi_start_queue(master);
- + if (ret)
- + dev_err(&master->dev, "queue restart failed\n");
- +
- + return ret;
- +}
- +EXPORT_SYMBOL_GPL(spi_master_resume);
- +
- static int __spi_master_match(struct device *dev, void *data)
- {
- struct spi_master *m;
- --- a/include/linux/spi/spi.h
- +++ b/include/linux/spi/spi.h
- @@ -22,6 +22,7 @@
- #include <linux/device.h>
- #include <linux/mod_devicetable.h>
- #include <linux/slab.h>
- +#include <linux/kthread.h>
-
- /*
- * INTERFACES between SPI master-side drivers and SPI infrastructure.
- @@ -235,6 +236,27 @@ static inline void spi_unregister_driver
- * the device whose settings are being modified.
- * @transfer: adds a message to the controller's transfer queue.
- * @cleanup: frees controller-specific state
- + * @queued: whether this master is providing an internal message queue
- + * @kworker: thread struct for message pump
- + * @kworker_task: pointer to task for message pump kworker thread
- + * @pump_messages: work struct for scheduling work to the message pump
- + * @queue_lock: spinlock to syncronise access to message queue
- + * @queue: message queue
- + * @cur_msg: the currently in-flight message
- + * @busy: message pump is busy
- + * @running: message pump is running
- + * @rt: whether this queue is set to run as a realtime task
- + * @prepare_transfer_hardware: a message will soon arrive from the queue
- + * so the subsystem requests the driver to prepare the transfer hardware
- + * by issuing this call
- + * @transfer_one_message: the subsystem calls the driver to transfer a single
- + * message while queuing transfers that arrive in the meantime. When the
- + * driver is finished with this message, it must call
- + * spi_finalize_current_message() so the subsystem can issue the next
- + * transfer
- + * @prepare_transfer_hardware: there are currently no more messages on the
- + * queue so the subsystem notifies the driver that it may relax the
- + * hardware by issuing this call
- *
- * Each SPI master controller can communicate with one or more @spi_device
- * children. These make a small bus, sharing MOSI, MISO and SCK signals
- @@ -318,6 +340,28 @@ struct spi_master {
-
- /* called on release() to free memory provided by spi_master */
- void (*cleanup)(struct spi_device *spi);
- +
- + /*
- + * These hooks are for drivers that want to use the generic
- + * master transfer queueing mechanism. If these are used, the
- + * transfer() function above must NOT be specified by the driver.
- + * Over time we expect SPI drivers to be phased over to this API.
- + */
- + bool queued;
- + struct kthread_worker kworker;
- + struct task_struct *kworker_task;
- + struct kthread_work pump_messages;
- + spinlock_t queue_lock;
- + struct list_head queue;
- + struct spi_message *cur_msg;
- + bool busy;
- + bool running;
- + bool rt;
- +
- + int (*prepare_transfer_hardware)(struct spi_master *master);
- + int (*transfer_one_message)(struct spi_master *master,
- + struct spi_message *mesg);
- + int (*unprepare_transfer_hardware)(struct spi_master *master);
- };
-
- static inline void *spi_master_get_devdata(struct spi_master *master)
- @@ -343,6 +387,13 @@ static inline void spi_master_put(struct
- put_device(&master->dev);
- }
-
- +/* PM calls that need to be issued by the driver */
- +extern int spi_master_suspend(struct spi_master *master);
- +extern int spi_master_resume(struct spi_master *master);
- +
- +/* Calls the driver make to interact with the message queue */
- +extern struct spi_message *spi_get_next_queued_message(struct spi_master *master);
- +extern void spi_finalize_current_message(struct spi_master *master);
-
- /* the spi driver core manages memory for the spi_master classdev */
- extern struct spi_master *
|