Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d4d4582 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'async-tx-for-linus' of git://lost.foo-projects.org/~dwillia2/git/iop into fix

* 'async-tx-for-linus' of git://lost.foo-projects.org/~dwillia2/git/iop:
  async_tx: allow architecture specific async_tx_find_channel implementations
  async_tx: replace 'int_en' with operation preparation flags
  async_tx: kill tx_set_src and tx_set_dest methods
  async_tx: kill ASYNC_TX_ASSUME_COHERENT
  iop-adma: use LIST_HEAD instead of LIST_HEAD_INIT
  async_tx: use LIST_HEAD instead of LIST_HEAD_INIT
  async_tx: fix compile breakage, mark do_async_xor __always_inline
parents 8f1bfa4c 47437b2c
Loading
Loading
Loading
Loading
+17 −21
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
 * @src: src page
 * @offset: offset in pages to start transaction
 * @len: length in bytes
 * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
 * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
 * @depend_tx: memcpy depends on the result of this transaction
 * @cb_fn: function to call when the memcpy completes
 * @cb_param: parameter to pass to the callback routine
@@ -46,33 +46,29 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
	struct dma_async_tx_descriptor *depend_tx,
	dma_async_tx_callback cb_fn, void *cb_param)
{
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY);
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY,
						      &dest, 1, &src, 1, len);
	struct dma_device *device = chan ? chan->device : NULL;
	int int_en = cb_fn ? 1 : 0;
	struct dma_async_tx_descriptor *tx = device ?
		device->device_prep_dma_memcpy(chan, len,
		int_en) : NULL;
	struct dma_async_tx_descriptor *tx = NULL;

	if (tx) { /* run the memcpy asynchronously */
		dma_addr_t addr;
		enum dma_data_direction dir;
	if (device) {
		dma_addr_t dma_dest, dma_src;
		unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;

		pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);

		dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
			DMA_NONE : DMA_FROM_DEVICE;

		addr = dma_map_page(device->dev, dest, dest_offset, len, dir);
		tx->tx_set_dest(addr, tx, 0);
		dma_dest = dma_map_page(device->dev, dest, dest_offset, len,
					DMA_FROM_DEVICE);

		dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
			DMA_NONE : DMA_TO_DEVICE;
		dma_src = dma_map_page(device->dev, src, src_offset, len,
				       DMA_TO_DEVICE);

		addr = dma_map_page(device->dev, src, src_offset, len, dir);
		tx->tx_set_src(addr, tx, 0);
		tx = device->device_prep_dma_memcpy(chan, dma_dest, dma_src,
						    len, dma_prep_flags);
	}

	if (tx) {
		pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
		async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
	} else { /* run the memcpy synchronously */
	} else {
		void *dest_buf, *src_buf;
		pr_debug("%s: (sync) len: %zu\n", __FUNCTION__, len);

+14 −14
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
 * @val: fill value
 * @offset: offset in pages to start transaction
 * @len: length in bytes
 * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
 * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
 * @depend_tx: memset depends on the result of this transaction
 * @cb_fn: function to call when the memcpy completes
 * @cb_param: parameter to pass to the callback routine
@@ -46,24 +46,24 @@ async_memset(struct page *dest, int val, unsigned int offset,
	struct dma_async_tx_descriptor *depend_tx,
	dma_async_tx_callback cb_fn, void *cb_param)
{
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET);
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET,
						      &dest, 1, NULL, 0, len);
	struct dma_device *device = chan ? chan->device : NULL;
	int int_en = cb_fn ? 1 : 0;
	struct dma_async_tx_descriptor *tx = device ?
		device->device_prep_dma_memset(chan, val, len,
			int_en) : NULL;
	struct dma_async_tx_descriptor *tx = NULL;

	if (tx) { /* run the memset asynchronously */
		dma_addr_t dma_addr;
		enum dma_data_direction dir;
	if (device) {
		dma_addr_t dma_dest;
		unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;

		pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
		dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
			DMA_NONE : DMA_FROM_DEVICE;
		dma_dest = dma_map_page(device->dev, dest, offset, len,
					DMA_FROM_DEVICE);

		dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
		tx->tx_set_dest(dma_addr, tx, 0);
		tx = device->device_prep_dma_memset(chan, dma_dest, val, len,
						    dma_prep_flags);
	}

	if (tx) {
		pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
		async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
	} else { /* run the memset synchronously */
		void *dest_buf;
+4 −5
Original line number Diff line number Diff line
@@ -57,8 +57,7 @@ static struct chan_ref_percpu *channel_table[DMA_TX_TYPE_END];
 */
static spinlock_t async_tx_lock;

static struct list_head
async_tx_master_list = LIST_HEAD_INIT(async_tx_master_list);
static LIST_HEAD(async_tx_master_list);

/* async_tx_issue_pending_all - start all transactions on all channels */
void async_tx_issue_pending_all(void)
@@ -362,13 +361,13 @@ static void __exit async_tx_exit(void)
}

/**
 * async_tx_find_channel - find a channel to carry out the operation or let
 * __async_tx_find_channel - find a channel to carry out the operation or let
 *	the transaction execute synchronously
 * @depend_tx: transaction dependency
 * @tx_type: transaction type
 */
struct dma_chan *
async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
__async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
	enum dma_transaction_type tx_type)
{
	/* see if we can keep the chain on one channel */
@@ -384,7 +383,7 @@ async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
	} else
		return NULL;
}
EXPORT_SYMBOL_GPL(async_tx_find_channel);
EXPORT_SYMBOL_GPL(__async_tx_find_channel);
#else
static int __init async_tx_init(void)
{
+75 −49
Original line number Diff line number Diff line
@@ -30,35 +30,51 @@
#include <linux/raid/xor.h>
#include <linux/async_tx.h>

static void
do_async_xor(struct dma_async_tx_descriptor *tx, struct dma_device *device,
/* do_async_xor - dma map the pages and perform the xor with an engine.
 * 	This routine is marked __always_inline so it can be compiled away
 * 	when CONFIG_DMA_ENGINE=n
 */
static __always_inline struct dma_async_tx_descriptor *
do_async_xor(struct dma_device *device,
	struct dma_chan *chan, struct page *dest, struct page **src_list,
	unsigned int offset, unsigned int src_cnt, size_t len,
	enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
	dma_async_tx_callback cb_fn, void *cb_param)
{
	dma_addr_t dma_addr;
	enum dma_data_direction dir;
	dma_addr_t dma_dest;
	dma_addr_t *dma_src = (dma_addr_t *) src_list;
	struct dma_async_tx_descriptor *tx;
	int i;
	unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;

	pr_debug("%s: len: %zu\n", __FUNCTION__, len);

	dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
		DMA_NONE : DMA_FROM_DEVICE;

	dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
	tx->tx_set_dest(dma_addr, tx, 0);
	dma_dest = dma_map_page(device->dev, dest, offset, len,
				DMA_FROM_DEVICE);

	dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
		DMA_NONE : DMA_TO_DEVICE;
	for (i = 0; i < src_cnt; i++)
		dma_src[i] = dma_map_page(device->dev, src_list[i], offset,
					  len, DMA_TO_DEVICE);

	for (i = 0; i < src_cnt; i++) {
		dma_addr = dma_map_page(device->dev, src_list[i],
			offset, len, dir);
		tx->tx_set_src(dma_addr, tx, i);
	/* Since we have clobbered the src_list we are committed
	 * to doing this asynchronously.  Drivers force forward progress
	 * in case they can not provide a descriptor
	 */
	tx = device->device_prep_dma_xor(chan, dma_dest, dma_src, src_cnt, len,
					 dma_prep_flags);
	if (!tx) {
		if (depend_tx)
			dma_wait_for_async_tx(depend_tx);

		while (!tx)
			tx = device->device_prep_dma_xor(chan, dma_dest,
							 dma_src, src_cnt, len,
							 dma_prep_flags);
	}

	async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);

	return tx;
}

static void
@@ -102,7 +118,7 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
 * @src_cnt: number of source pages
 * @len: length in bytes
 * @flags: ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DEST,
 *	ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
 *	ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
 * @depend_tx: xor depends on the result of this transaction.
 * @cb_fn: function to call when the xor completes
 * @cb_param: parameter to pass to the callback routine
@@ -113,14 +129,16 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
	struct dma_async_tx_descriptor *depend_tx,
	dma_async_tx_callback cb_fn, void *cb_param)
{
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR);
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR,
						      &dest, 1, src_list,
						      src_cnt, len);
	struct dma_device *device = chan ? chan->device : NULL;
	struct dma_async_tx_descriptor *tx = NULL;
	dma_async_tx_callback _cb_fn;
	void *_cb_param;
	unsigned long local_flags;
	int xor_src_cnt;
	int i = 0, src_off = 0, int_en;
	int i = 0, src_off = 0;

	BUG_ON(src_cnt <= 1);

@@ -140,20 +158,11 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
				_cb_param = cb_param;
			}

			int_en = _cb_fn ? 1 : 0;

			tx = device->device_prep_dma_xor(
				chan, xor_src_cnt, len, int_en);

			if (tx) {
				do_async_xor(tx, device, chan, dest,
				&src_list[src_off], offset, xor_src_cnt, len,
				local_flags, depend_tx, _cb_fn,
				_cb_param);
			} else /* fall through */
				goto xor_sync;
			tx = do_async_xor(device, chan, dest,
					  &src_list[src_off], offset,
					  xor_src_cnt, len, local_flags,
					  depend_tx, _cb_fn, _cb_param);
		} else { /* run the xor synchronously */
xor_sync:
			/* in the sync case the dest is an implied source
			 * (assumes the dest is at the src_off index)
			 */
@@ -242,7 +251,7 @@ static int page_is_zero(struct page *p, unsigned int offset, size_t len)
 * @src_cnt: number of source pages
 * @len: length in bytes
 * @result: 0 if sum == 0 else non-zero
 * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
 * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
 * @depend_tx: xor depends on the result of this transaction.
 * @cb_fn: function to call when the xor completes
 * @cb_param: parameter to pass to the callback routine
@@ -254,29 +263,36 @@ async_xor_zero_sum(struct page *dest, struct page **src_list,
	struct dma_async_tx_descriptor *depend_tx,
	dma_async_tx_callback cb_fn, void *cb_param)
{
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM);
	struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM,
						      &dest, 1, src_list,
						      src_cnt, len);
	struct dma_device *device = chan ? chan->device : NULL;
	int int_en = cb_fn ? 1 : 0;
	struct dma_async_tx_descriptor *tx = device ?
		device->device_prep_dma_zero_sum(chan, src_cnt, len, result,
			int_en) : NULL;
	int i;
	struct dma_async_tx_descriptor *tx = NULL;

	BUG_ON(src_cnt <= 1);

	if (tx) {
		dma_addr_t dma_addr;
		enum dma_data_direction dir;
	if (device) {
		dma_addr_t *dma_src = (dma_addr_t *) src_list;
		unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
		int i;

		pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);

		dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
			DMA_NONE : DMA_TO_DEVICE;

		for (i = 0; i < src_cnt; i++) {
			dma_addr = dma_map_page(device->dev, src_list[i],
				offset, len, dir);
			tx->tx_set_src(dma_addr, tx, i);
		for (i = 0; i < src_cnt; i++)
			dma_src[i] = dma_map_page(device->dev, src_list[i],
						  offset, len, DMA_TO_DEVICE);

		tx = device->device_prep_dma_zero_sum(chan, dma_src, src_cnt,
						      len, result,
						      dma_prep_flags);
		if (!tx) {
			if (depend_tx)
				dma_wait_for_async_tx(depend_tx);

			while (!tx)
				tx = device->device_prep_dma_zero_sum(chan,
					dma_src, src_cnt, len, result,
					dma_prep_flags);
		}

		async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
@@ -311,6 +327,16 @@ EXPORT_SYMBOL_GPL(async_xor_zero_sum);

static int __init async_xor_init(void)
{
	#ifdef CONFIG_DMA_ENGINE
	/* To conserve stack space the input src_list (array of page pointers)
	 * is reused to hold the array of dma addresses passed to the driver.
	 * This conversion is only possible when dma_addr_t is less than the
	 * the size of a pointer.  HIGHMEM64G is known to violate this
	 * assumption.
	 */
	BUILD_BUG_ON(sizeof(dma_addr_t) > sizeof(struct page *));
	#endif

	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
menuconfig DMADEVICES
	bool "DMA Engine support"
	depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
	depends on !HIGHMEM64G
	help
	  DMA engines can do asynchronous data transfers without
	  involving the host CPU.  Currently, this framework can be
Loading