linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: linux-kernel@vger.kernel.org
Cc: Grant Likely <grant.likely@secretlab.ca>,
	Eric Miao <eric.y.miao@gmail.com>,
	Russell King <linux@arm.linux.org.uk>,
	Haojian Zhuang <haojian.zhuang@linaro.org>,
	Mark Brown <broonie@opensource.wolfsonmicro.com>,
	Linus Walleij <linus.walleij@linaro.org>,
	"Rafael J. Wysocki" <rafael.j.wysocki@intel.com>,
	chao.bi@intel.com,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	cxie4@marvell.com, ytang5@marvell.com,
	Mika Westerberg <mika.westerberg@linux.intel.com>
Subject: [PATCH v3 03/10] spi/pxa2xx: convert to the pump message infrastructure
Date: Tue, 22 Jan 2013 12:26:26 +0200	[thread overview]
Message-ID: <1358850393-23111-4-git-send-email-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <1358850393-23111-1-git-send-email-mika.westerberg@linux.intel.com>

The SPI core provides infrastructure for standard message queueing so use
that instead of handling everything in the driver. This simplifies the
driver.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/spi/spi-pxa2xx.c |  212 +++-------------------------------------------
 1 file changed, 12 insertions(+), 200 deletions(-)

diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index ef0a786..a241891 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -85,9 +85,6 @@ DEFINE_SSP_REG(SSPSP, 0x2c)
 #define DONE_STATE ((void*)2)
 #define ERROR_STATE ((void*)-1)
 
-#define QUEUE_RUNNING 0
-#define QUEUE_STOPPED 1
-
 struct driver_data {
 	/* Driver model hookup */
 	struct platform_device *pdev;
@@ -117,14 +114,6 @@ struct driver_data {
 	u32 clear_sr;
 	u32 mask_sr;
 
-	/* Driver message queue */
-	struct workqueue_struct	*workqueue;
-	struct work_struct pump_messages;
-	spinlock_t lock;
-	struct list_head queue;
-	int busy;
-	int run;
-
 	/* Message Transfer pump */
 	struct tasklet_struct pump_transfers;
 
@@ -173,8 +162,6 @@ struct chip_data {
 	void (*cs_control)(u32 command);
 };
 
-static void pump_messages(struct work_struct *work);
-
 static void cs_assert(struct driver_data *drv_data)
 {
 	struct chip_data *chip = drv_data->cur_chip;
@@ -444,15 +431,11 @@ static void unmap_dma_buffers(struct driver_data *drv_data)
 static void giveback(struct driver_data *drv_data)
 {
 	struct spi_transfer* last_transfer;
-	unsigned long flags;
 	struct spi_message *msg;
 
-	spin_lock_irqsave(&drv_data->lock, flags);
 	msg = drv_data->cur_msg;
 	drv_data->cur_msg = NULL;
 	drv_data->cur_transfer = NULL;
-	queue_work(drv_data->workqueue, &drv_data->pump_messages);
-	spin_unlock_irqrestore(&drv_data->lock, flags);
 
 	last_transfer = list_entry(msg->transfers.prev,
 					struct spi_transfer,
@@ -481,13 +464,7 @@ static void giveback(struct driver_data *drv_data)
 		 */
 
 		/* get a pointer to the next message, if any */
-		spin_lock_irqsave(&drv_data->lock, flags);
-		if (list_empty(&drv_data->queue))
-			next_msg = NULL;
-		else
-			next_msg = list_entry(drv_data->queue.next,
-					struct spi_message, queue);
-		spin_unlock_irqrestore(&drv_data->lock, flags);
+		next_msg = spi_get_next_queued_message(drv_data->master);
 
 		/* see if the next and current messages point
 		 * to the same chip
@@ -498,10 +475,7 @@ static void giveback(struct driver_data *drv_data)
 			cs_deassert(drv_data);
 	}
 
-	msg->state = NULL;
-	if (msg->complete)
-		msg->complete(msg->context);
-
+	spi_finalize_current_message(drv_data->master);
 	drv_data->cur_chip = NULL;
 }
 
@@ -1176,31 +1150,12 @@ static void pump_transfers(unsigned long data)
 	write_SSCR1(cr1, reg);
 }
 
-static void pump_messages(struct work_struct *work)
+static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
+					   struct spi_message *msg)
 {
-	struct driver_data *drv_data =
-		container_of(work, struct driver_data, pump_messages);
-	unsigned long flags;
-
-	/* Lock queue and check for queue work */
-	spin_lock_irqsave(&drv_data->lock, flags);
-	if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
-		drv_data->busy = 0;
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return;
-	}
-
-	/* Make sure we are not already running a message */
-	if (drv_data->cur_msg) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return;
-	}
-
-	/* Extract head of queue */
-	drv_data->cur_msg = list_entry(drv_data->queue.next,
-					struct spi_message, queue);
-	list_del_init(&drv_data->cur_msg->queue);
+	struct driver_data *drv_data = spi_master_get_devdata(master);
 
+	drv_data->cur_msg = msg;
 	/* Initial message state*/
 	drv_data->cur_msg->state = START_STATE;
 	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
@@ -1213,34 +1168,6 @@ static void pump_messages(struct work_struct *work)
 
 	/* Mark as busy and launch transfers */
 	tasklet_schedule(&drv_data->pump_transfers);
-
-	drv_data->busy = 1;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-}
-
-static int transfer(struct spi_device *spi, struct spi_message *msg)
-{
-	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
-	unsigned long flags;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-
-	if (drv_data->run == QUEUE_STOPPED) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return -ESHUTDOWN;
-	}
-
-	msg->actual_length = 0;
-	msg->status = -EINPROGRESS;
-	msg->state = START_STATE;
-
-	list_add_tail(&msg->queue, &drv_data->queue);
-
-	if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
-		queue_work(drv_data->workqueue, &drv_data->pump_messages);
-
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-
 	return 0;
 }
 
@@ -1438,94 +1365,6 @@ static void cleanup(struct spi_device *spi)
 	kfree(chip);
 }
 
-static int init_queue(struct driver_data *drv_data)
-{
-	INIT_LIST_HEAD(&drv_data->queue);
-	spin_lock_init(&drv_data->lock);
-
-	drv_data->run = QUEUE_STOPPED;
-	drv_data->busy = 0;
-
-	tasklet_init(&drv_data->pump_transfers,
-			pump_transfers,	(unsigned long)drv_data);
-
-	INIT_WORK(&drv_data->pump_messages, pump_messages);
-	drv_data->workqueue = create_singlethread_workqueue(
-				dev_name(drv_data->master->dev.parent));
-	if (drv_data->workqueue == NULL)
-		return -EBUSY;
-
-	return 0;
-}
-
-static int start_queue(struct driver_data *drv_data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-
-	if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return -EBUSY;
-	}
-
-	drv_data->run = QUEUE_RUNNING;
-	drv_data->cur_msg = NULL;
-	drv_data->cur_transfer = NULL;
-	drv_data->cur_chip = NULL;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-
-	queue_work(drv_data->workqueue, &drv_data->pump_messages);
-
-	return 0;
-}
-
-static int stop_queue(struct driver_data *drv_data)
-{
-	unsigned long flags;
-	unsigned limit = 500;
-	int status = 0;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-
-	/* This is a bit lame, but is optimized for the common execution path.
-	 * A wait_queue on the drv_data->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 */
-	drv_data->run = QUEUE_STOPPED;
-	while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		msleep(10);
-		spin_lock_irqsave(&drv_data->lock, flags);
-	}
-
-	if (!list_empty(&drv_data->queue) || drv_data->busy)
-		status = -EBUSY;
-
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-
-	return status;
-}
-
-static int destroy_queue(struct driver_data *drv_data)
-{
-	int status;
-
-	status = stop_queue(drv_data);
-	/* we are unloading the module or failing to load (only two calls
-	 * to this routine), and neither call can handle a return value.
-	 * However, destroy_workqueue calls flush_workqueue, and that 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 destroy_workqueue, so return anyway. */
-	if (status != 0)
-		return status;
-
-	destroy_workqueue(drv_data->workqueue);
-
-	return 0;
-}
-
 static int pxa2xx_spi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1573,7 +1412,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 	master->dma_alignment = DMA_ALIGNMENT;
 	master->cleanup = cleanup;
 	master->setup = setup;
-	master->transfer = transfer;
+	master->transfer_one_message = pxa2xx_spi_transfer_one_message;
 
 	drv_data->ssp_type = ssp->type;
 	drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
@@ -1646,31 +1485,19 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 		write_SSTO(0, drv_data->ioaddr);
 	write_SSPSP(0, drv_data->ioaddr);
 
-	/* Initial and start queue */
-	status = init_queue(drv_data);
-	if (status != 0) {
-		dev_err(&pdev->dev, "problem initializing queue\n");
-		goto out_error_clock_enabled;
-	}
-	status = start_queue(drv_data);
-	if (status != 0) {
-		dev_err(&pdev->dev, "problem starting queue\n");
-		goto out_error_clock_enabled;
-	}
+	tasklet_init(&drv_data->pump_transfers, pump_transfers,
+		     (unsigned long)drv_data);
 
 	/* Register with the SPI framework */
 	platform_set_drvdata(pdev, drv_data);
 	status = spi_register_master(master);
 	if (status != 0) {
 		dev_err(&pdev->dev, "problem registering spi master\n");
-		goto out_error_queue_alloc;
+		goto out_error_clock_enabled;
 	}
 
 	return status;
 
-out_error_queue_alloc:
-	destroy_queue(drv_data);
-
 out_error_clock_enabled:
 	clk_disable(ssp->clk);
 
@@ -1693,26 +1520,11 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
 {
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
 	struct ssp_device *ssp;
-	int status = 0;
 
 	if (!drv_data)
 		return 0;
 	ssp = drv_data->ssp;
 
-	/* Remove the queue */
-	status = destroy_queue(drv_data);
-	if (status != 0)
-		/* the kernel does not check the return status of this
-		 * this routine (mod->exit, within the kernel).  Therefore
-		 * nothing is gained by returning from here, the module is
-		 * going away regardless, and we should not leave any more
-		 * resources allocated than necessary.  We cannot free the
-		 * message memory in drv_data->queue, but we can release the
-		 * resources below.  I think the kernel should honor -EBUSY
-		 * returns but... */
-		dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
-			"complete, message memory not freed\n");
-
 	/* Disable the SSP at the peripheral and SOC level */
 	write_SSCR0(0, drv_data->ioaddr);
 	clk_disable(ssp->clk);
@@ -1755,7 +1567,7 @@ static int pxa2xx_spi_suspend(struct device *dev)
 	struct ssp_device *ssp = drv_data->ssp;
 	int status = 0;
 
-	status = stop_queue(drv_data);
+	status = spi_master_suspend(drv_data->master);
 	if (status != 0)
 		return status;
 	write_SSCR0(0, drv_data->ioaddr);
@@ -1781,7 +1593,7 @@ static int pxa2xx_spi_resume(struct device *dev)
 	clk_enable(ssp->clk);
 
 	/* Start the queue running */
-	status = start_queue(drv_data);
+	status = spi_master_resume(drv_data->master);
 	if (status != 0) {
 		dev_err(dev, "problem starting queue (%d)\n", status);
 		return status;
-- 
1.7.10.4


  parent reply	other threads:[~2013-01-22 10:26 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-22 10:26 [PATCH v3 00/10] spi/pxa2xx: add Intel Lynxpoint SPI controller support Mika Westerberg
2013-01-22 10:26 ` [PATCH v3 01/10] spi/pxa2xx: allow building on a 64-bit kernel Mika Westerberg
2013-01-26  7:21   ` Mark Brown
2013-01-22 10:26 ` [PATCH v3 02/10] spi/pxa2xx: fix warnings when compiling " Mika Westerberg
2013-01-26  7:22   ` Mark Brown
2013-01-22 10:26 ` Mika Westerberg [this message]
2013-01-26  7:23   ` [PATCH v3 03/10] spi/pxa2xx: convert to the pump message infrastructure Mark Brown
2013-01-22 10:26 ` [PATCH v3 04/10] spi/pxa2xx: convert to the common clk framework Mika Westerberg
2013-01-26  7:23   ` Mark Brown
2013-01-22 10:26 ` [PATCH v3 05/10] spi/pxa2xx: break out the private DMA API usage into a separate file Mika Westerberg
2013-02-04 19:43   ` Linus Walleij
2013-02-05  6:15     ` Mika Westerberg
2013-02-08 12:13   ` Mark Brown
2013-01-22 10:26 ` [PATCH v3 06/10] spi/pxa2xx: add support for DMA engine Mika Westerberg
2013-02-04 19:46   ` Linus Walleij
2013-02-08 12:13   ` Mark Brown
2013-01-22 10:26 ` [PATCH v3 07/10] spi/pxa2xx: add support for runtime PM Mika Westerberg
2013-02-08 12:14   ` Mark Brown
2013-01-22 10:26 ` [PATCH v3 08/10] spi/pxa2xx: add support for SPI_LOOP Mika Westerberg
2013-02-08 12:14   ` Mark Brown
2013-01-22 10:26 ` [PATCH v3 09/10] spi/pxa2xx: add support for Intel Low Power Subsystem SPI Mika Westerberg
2013-02-08 13:14   ` Mark Brown
2013-01-22 10:26 ` [PATCH v3 10/10] spi/pxa2xx: add support for Lynxpoint SPI controllers Mika Westerberg
2013-02-08 13:16   ` Mark Brown
     [not found] ` <CACb1VKtD+pc5cAJAqBg82uCXH_icm9fk1yLB_UnwmEq4Lq-NVQ@mail.gmail.com>
2013-02-01 10:22   ` [PATCH v3 00/10] spi/pxa2xx: add Intel Lynxpoint SPI controller support Mika Westerberg
2013-02-04  9:45     ` Mark Brown
2013-02-04  9:52       ` Mika Westerberg
2013-02-08 21:37         ` Linus Walleij
2013-02-09  3:43           ` Mika Westerberg
2013-02-08  7:34       ` Mika Westerberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1358850393-23111-4-git-send-email-mika.westerberg@linux.intel.com \
    --to=mika.westerberg@linux.intel.com \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=chao.bi@intel.com \
    --cc=cxie4@marvell.com \
    --cc=eric.y.miao@gmail.com \
    --cc=grant.likely@secretlab.ca \
    --cc=haojian.zhuang@linaro.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=rafael.j.wysocki@intel.com \
    --cc=ytang5@marvell.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).