Re: [PATCH v3 02/34] dmaengine: back channel BH helpers with WQ_BH

Vinod Koul <[email protected]>
Newsgroups org.kernel.vger.dmaengine,org.kernel.vger.linux-kernel
Message-ID <antgvm7jj7eBtDjR@vaman>
On 10-08-26, 11:09, Allen Pais wrote:
> Replace the tasklet implementation of the channel BH helpers with a
> dedicated WQ_BH | WQ_PERCPU workqueue. The public dmaengine_*_bh() API and
> its softirq execution context remain unchanged.
> 
> Keep the workqueue operations internal to dmaengine. Drain scheduled work
> in dmaengine_kill_bh() to preserve the completion semantics of
> tasklet_kill().

Thanks Allen, this lgtm. I am asking for to test the series and report
any issues. If all is good, I plan to pick this up in 3 weeks time after
rc1. 

> 
> Signed-off-by: Allen Pais <[email protected]>
> ---
>  drivers/dma/dmaengine.c   | 59 ++++++++++++++++++++++++++++++++-------
>  include/linux/dmaengine.h | 10 +++----
>  2 files changed, 54 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> index d8fc7eb71b48..e00f73a18e99 100644
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -54,6 +54,7 @@
>  #include <linux/rcupdate.h>
>  #include <linux/slab.h>
>  #include <linux/spinlock.h>
> +#include <linux/workqueue.h>
>  
>  #include "dmaengine.h"
>  
> @@ -61,6 +62,7 @@ static DEFINE_MUTEX(dma_list_mutex);
>  static DEFINE_IDA(dma_ida);
>  static LIST_HEAD(dma_device_list);
>  static long dmaengine_ref_count;
> +static struct workqueue_struct *dmaengine_bh_wq;
>  
>  /* --- debugfs implementation --- */
>  #ifdef CONFIG_DEBUG_FS
> @@ -1428,9 +1430,34 @@ static void dmaengine_destroy_unmap_pool(void)
>  	}
>  }
>  
> -static void dma_chan_bh_entry(struct tasklet_struct *tasklet)
> +static void dmaengine_destroy_bh_wq(void)
>  {
> -	struct dma_chan *chan = from_tasklet(chan, tasklet, bh_tasklet);
> +	if (!dmaengine_bh_wq)
> +		return;
> +
> +	destroy_workqueue(dmaengine_bh_wq);
> +	dmaengine_bh_wq = NULL;
> +}
> +
> +static bool dmaengine_queue_bh_work(struct work_struct *work)
> +{
> +	if (WARN_ON(!dmaengine_bh_wq))
> +		return false;
> +
> +	return queue_work(dmaengine_bh_wq, work);
> +}
> +
> +static void dmaengine_flush_bh_work(struct work_struct *work)
> +{
> +	if (!work)
> +		return;
> +
> +	flush_work(work);
> +}
> +
> +static void dma_chan_bh_entry(struct work_struct *work)
> +{
> +	struct dma_chan *chan = container_of(work, struct dma_chan, bh_work);
>  	dmaengine_bh_work_fn fn = READ_ONCE(chan->bh_work_fn);
>  
>  	if (fn)
> @@ -1446,7 +1473,7 @@ void dmaengine_init_bh(struct dma_chan *chan, dmaengine_bh_work_fn fn)
>  		return;
>  
>  	chan->bh_work_fn = fn;
> -	tasklet_setup(&chan->bh_tasklet, dma_chan_bh_entry);
> +	INIT_WORK(&chan->bh_work, dma_chan_bh_entry);
>  	chan->bh_work_initialized = true;
>  }
>  EXPORT_SYMBOL_GPL(dmaengine_init_bh);
> @@ -1456,8 +1483,7 @@ bool dmaengine_schedule_bh(struct dma_chan *chan)
>  	if (WARN_ON(!chan->bh_work_initialized))
>  		return false;
>  
> -	tasklet_schedule(&chan->bh_tasklet);
> -	return true;
> +	return dmaengine_queue_bh_work(&chan->bh_work);
>  }
>  EXPORT_SYMBOL_GPL(dmaengine_schedule_bh);
>  
> @@ -1466,7 +1492,7 @@ void dmaengine_kill_bh(struct dma_chan *chan)
>  	if (!chan->bh_work_initialized)
>  		return;
>  
> -	tasklet_kill(&chan->bh_tasklet);
> +	dmaengine_flush_bh_work(&chan->bh_work);
>  }
>  EXPORT_SYMBOL_GPL(dmaengine_kill_bh);
>  
> @@ -1666,15 +1692,28 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies);
>  
>  static int __init dma_bus_init(void)
>  {
> -	int err = dmaengine_init_unmap_pool();
> +	int err;
>  
> +	dmaengine_bh_wq = alloc_workqueue("dmaengine_bh",
> +					  WQ_BH | WQ_PERCPU, 0);
> +	if (!dmaengine_bh_wq)
> +		return -ENOMEM;
> +
> +	err = dmaengine_init_unmap_pool();
>  	if (err)
> -		return err;
> +		goto err_destroy_wq;
>  
>  	err = class_register(&dma_devclass);
> -	if (!err)
> -		dmaengine_debugfs_init();
> +	if (err)
> +		goto err_destroy_pool;
>  
> +	dmaengine_debugfs_init();
> +	return 0;
> +
> +err_destroy_pool:
> +	dmaengine_destroy_unmap_pool();
> +err_destroy_wq:
> +	dmaengine_destroy_bh_wq();
>  	return err;
>  }
>  arch_initcall(dma_bus_init);
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index a1437bdbda9b..9f1a5405f6b0 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -12,7 +12,7 @@
>  #include <linux/scatterlist.h>
>  #include <linux/bitmap.h>
>  #include <linux/types.h>
> -#include <linux/interrupt.h>
> +#include <linux/workqueue.h>
>  #include <asm/page.h>
>  
>  /**
> @@ -339,9 +339,9 @@ struct dma_router {
>   * @router: pointer to the DMA router structure
>   * @route_data: channel specific data for the router
>   * @private: private data for certain client-channel associations
> - * @bh_tasklet: bottom-half tasklet stored per-channel
> - * @bh_work_fn: callback executed when @bh_tasklet runs
> - * @bh_work_initialized: indicates whether @bh_tasklet has been initialized
> + * @bh_work: bottom-half work item stored per-channel
> + * @bh_work_fn: callback executed when @bh_work runs
> + * @bh_work_initialized: indicates whether @bh_work has been initialized
>   */
>  struct dma_chan {
>  	struct dma_device *device;
> @@ -367,7 +367,7 @@ struct dma_chan {
>  	void *route_data;
>  
>  	void *private;
> -	struct tasklet_struct bh_tasklet;
> +	struct work_struct bh_work;
>  	dmaengine_bh_work_fn bh_work_fn;
>  	bool bh_work_initialized;
>  };
> -- 
> 2.43.0

-- 
~Vinod
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.