From patchwork Fri Jan 31 10:07:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baruch Siach X-Patchwork-Id: 3560901 Return-Path: X-Original-To: patchwork-linux-spi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 2EF58C02DC for ; Fri, 31 Jan 2014 10:08:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2969C2021A for ; Fri, 31 Jan 2014 10:08:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1BFB92021B for ; Fri, 31 Jan 2014 10:08:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754084AbaAaKIg (ORCPT ); Fri, 31 Jan 2014 05:08:36 -0500 Received: from guitar.tcltek.co.il ([192.115.133.116]:44416 "EHLO mx.tkos.co.il" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754085AbaAaKIe (ORCPT ); Fri, 31 Jan 2014 05:08:34 -0500 Received: from tarshish.tkos.co.il (unknown [10.0.8.6]) by mx.tkos.co.il (Postfix) with ESMTPSA id 0E7D3440A96; Fri, 31 Jan 2014 12:08:30 +0200 (IST) From: Baruch Siach To: Mark Brown Cc: linux-spi@vger.kernel.org, Feng Tang , Baruch Siach Subject: [PATCH v3 1/5] spi: dw: migrate to generic queue infrastructure Date: Fri, 31 Jan 2014 12:07:44 +0200 Message-Id: <22eae102a8ee67441110bec82129a1b6597b44a8.1391162172.git.baruch@tkos.co.il> X-Mailer: git-send-email 1.8.5.3 In-Reply-To: References: Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Baruch Siach --- drivers/spi/spi-dw.c | 183 ++++----------------------------------------------- drivers/spi/spi-dw.h | 8 --- 2 files changed, 12 insertions(+), 179 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index bf98d63d92b3..cd05c0050325 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -36,9 +36,6 @@ #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) -#define QUEUE_RUNNING 0 -#define QUEUE_STOPPED 1 - #define MRST_SPI_DEASSERT 0 #define MRST_SPI_ASSERT 1 @@ -263,18 +260,14 @@ static int map_dma_buffers(struct dw_spi *dws) static void giveback(struct dw_spi *dws) { struct spi_transfer *last_transfer; - unsigned long flags; struct spi_message *msg; - spin_lock_irqsave(&dws->lock, flags); msg = dws->cur_msg; dws->cur_msg = NULL; dws->cur_transfer = NULL; dws->prev_chip = dws->cur_chip; dws->cur_chip = NULL; dws->dma_mapped = 0; - queue_work(dws->workqueue, &dws->pump_messages); - spin_unlock_irqrestore(&dws->lock, flags); last_transfer = list_entry(msg->transfers.prev, struct spi_transfer, @@ -283,9 +276,7 @@ static void giveback(struct dw_spi *dws) if (!last_transfer->cs_change && dws->cs_control) dws->cs_control(MRST_SPI_DEASSERT); - msg->state = NULL; - if (msg->complete) - msg->complete(msg->context); + spi_finalize_current_message(dws->master); } static void int_error_stop(struct dw_spi *dws, const char *msg) @@ -536,30 +527,12 @@ early_exit: return; } -static void pump_messages(struct work_struct *work) +static int dw_spi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) { - struct dw_spi *dws = - container_of(work, struct dw_spi, pump_messages); - unsigned long flags; - - /* Lock queue and check for queue work */ - spin_lock_irqsave(&dws->lock, flags); - if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) { - dws->busy = 0; - spin_unlock_irqrestore(&dws->lock, flags); - return; - } - - /* Make sure we are not already running a message */ - if (dws->cur_msg) { - spin_unlock_irqrestore(&dws->lock, flags); - return; - } - - /* Extract head of queue */ - dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue); - list_del_init(&dws->cur_msg->queue); + struct dw_spi *dws = spi_master_get_devdata(master); + dws->cur_msg = msg; /* Initial message state*/ dws->cur_msg->state = START_STATE; dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, @@ -567,46 +540,9 @@ static void pump_messages(struct work_struct *work) transfer_list); dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); - /* Mark as busy and launch transfers */ + /* Launch transfers */ tasklet_schedule(&dws->pump_transfers); - dws->busy = 1; - spin_unlock_irqrestore(&dws->lock, flags); -} - -/* spi_device use this to queue in their spi_msg */ -static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg) -{ - struct dw_spi *dws = spi_master_get_devdata(spi->master); - unsigned long flags; - - spin_lock_irqsave(&dws->lock, flags); - - if (dws->run == QUEUE_STOPPED) { - spin_unlock_irqrestore(&dws->lock, flags); - return -ESHUTDOWN; - } - - msg->actual_length = 0; - msg->status = -EINPROGRESS; - msg->state = START_STATE; - - list_add_tail(&msg->queue, &dws->queue); - - if (dws->run == QUEUE_RUNNING && !dws->busy) { - - if (dws->cur_transfer || dws->cur_msg) - queue_work(dws->workqueue, - &dws->pump_messages); - else { - /* If no other data transaction in air, just go */ - spin_unlock_irqrestore(&dws->lock, flags); - pump_messages(&dws->pump_messages); - return 0; - } - } - - spin_unlock_irqrestore(&dws->lock, flags); return 0; } @@ -677,81 +613,6 @@ static void dw_spi_cleanup(struct spi_device *spi) kfree(chip); } -static int init_queue(struct dw_spi *dws) -{ - INIT_LIST_HEAD(&dws->queue); - spin_lock_init(&dws->lock); - - dws->run = QUEUE_STOPPED; - dws->busy = 0; - - tasklet_init(&dws->pump_transfers, - pump_transfers, (unsigned long)dws); - - INIT_WORK(&dws->pump_messages, pump_messages); - dws->workqueue = create_singlethread_workqueue( - dev_name(dws->master->dev.parent)); - if (dws->workqueue == NULL) - return -EBUSY; - - return 0; -} - -static int start_queue(struct dw_spi *dws) -{ - unsigned long flags; - - spin_lock_irqsave(&dws->lock, flags); - - if (dws->run == QUEUE_RUNNING || dws->busy) { - spin_unlock_irqrestore(&dws->lock, flags); - return -EBUSY; - } - - dws->run = QUEUE_RUNNING; - dws->cur_msg = NULL; - dws->cur_transfer = NULL; - dws->cur_chip = NULL; - dws->prev_chip = NULL; - spin_unlock_irqrestore(&dws->lock, flags); - - queue_work(dws->workqueue, &dws->pump_messages); - - return 0; -} - -static int stop_queue(struct dw_spi *dws) -{ - unsigned long flags; - unsigned limit = 50; - int status = 0; - - spin_lock_irqsave(&dws->lock, flags); - dws->run = QUEUE_STOPPED; - while ((!list_empty(&dws->queue) || dws->busy) && limit--) { - spin_unlock_irqrestore(&dws->lock, flags); - msleep(10); - spin_lock_irqsave(&dws->lock, flags); - } - - if (!list_empty(&dws->queue) || dws->busy) - status = -EBUSY; - spin_unlock_irqrestore(&dws->lock, flags); - - return status; -} - -static int destroy_queue(struct dw_spi *dws) -{ - int status; - - status = stop_queue(dws); - if (status != 0) - return status; - destroy_workqueue(dws->workqueue); - return 0; -} - /* Restart the controller, disable all interrupts, clean rx fifo */ static void spi_hw_init(struct dw_spi *dws) { @@ -808,7 +669,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->num_chipselect = dws->num_cs; master->cleanup = dw_spi_cleanup; master->setup = dw_spi_setup; - master->transfer = dw_spi_transfer; + master->transfer_one_message = dw_spi_transfer_one_message; /* Basic HW init */ spi_hw_init(dws); @@ -821,33 +682,21 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) } } - /* Initial and start queue */ - ret = init_queue(dws); - if (ret) { - dev_err(&master->dev, "problem initializing queue\n"); - goto err_diable_hw; - } - ret = start_queue(dws); - if (ret) { - dev_err(&master->dev, "problem starting queue\n"); - goto err_diable_hw; - } + tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws); spi_master_set_devdata(master, dws); ret = devm_spi_register_master(dev, master); if (ret) { dev_err(&master->dev, "problem registering spi master\n"); - goto err_queue_alloc; + goto err_dma_exit; } mrst_spi_debugfs_init(dws); return 0; -err_queue_alloc: - destroy_queue(dws); +err_dma_exit: if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); -err_diable_hw: spi_enable_chip(dws, 0); err_free_master: spi_master_put(master); @@ -857,18 +706,10 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host); void dw_spi_remove_host(struct dw_spi *dws) { - int status = 0; - if (!dws) return; mrst_spi_debugfs_remove(dws); - /* Remove the queue */ - status = destroy_queue(dws); - if (status != 0) - dev_err(&dws->master->dev, - "dw_spi_remove: workqueue will not complete, message memory not freed\n"); - if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); spi_enable_chip(dws, 0); @@ -881,7 +722,7 @@ int dw_spi_suspend_host(struct dw_spi *dws) { int ret = 0; - ret = stop_queue(dws); + ret = spi_master_suspend(dws->master); if (ret) return ret; spi_enable_chip(dws, 0); @@ -895,7 +736,7 @@ int dw_spi_resume_host(struct dw_spi *dws) int ret; spi_hw_init(dws); - ret = start_queue(dws); + ret = spi_master_resume(dws->master); if (ret) dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); return ret; diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 587643dae11e..3fd7ab599ab4 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -104,14 +104,6 @@ struct dw_spi { u16 bus_num; u16 num_cs; /* supported slave numbers */ - /* 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;