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

Commit df12a317 authored by Vinod Koul's avatar Vinod Koul
Browse files


Pull dmaengine changes from Dan

1/ Bartlomiej and Dan finalized a rework of the dma address unmap
   implementation.

2/ In the course of testing 1/ a collection of enhancements to dmatest
   fell out.  Notably basic performance statistics, and fixed / enhanced
   test control through new module parameters 'run', 'wait', 'noverify',
   and 'verbose'.  Thanks to Andriy and Linus for their review.

3/ Testing the raid related corner cases of 1/ triggered bugs in the
   recently added 16-source operation support in the ioatdma driver.

4/ Some minor fixes / cleanups to mv_xor and ioatdma.

Conflicts:
	drivers/dma/dmatest.c

Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parents 2f986ec6 82a1402e
Loading
Loading
Loading
Loading
+41 −31
Original line number Original line Diff line number Diff line
@@ -15,39 +15,48 @@ be built as module or inside kernel. Let's consider those cases.


	Part 2 - When dmatest is built as a module...
	Part 2 - When dmatest is built as a module...


After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest
folder with nodes will be created. There are two important files located. First
is the 'run' node that controls run and stop phases of the test, and the second
one, 'results', is used to get the test case results.

Note that in this case test will not run on load automatically.

Example of usage:
Example of usage:
	% modprobe dmatest channel=dma0chan0 timeout=2000 iterations=1 run=1

...or:
	% modprobe dmatest
	% echo dma0chan0 > /sys/module/dmatest/parameters/channel
	% echo dma0chan0 > /sys/module/dmatest/parameters/channel
	% echo 2000 > /sys/module/dmatest/parameters/timeout
	% echo 2000 > /sys/module/dmatest/parameters/timeout
	% echo 1 > /sys/module/dmatest/parameters/iterations
	% echo 1 > /sys/module/dmatest/parameters/iterations
	% echo 1 > /sys/kernel/debug/dmatest/run
	% echo 1 > /sys/module/dmatest/parameters/run

...or on the kernel command line:

	dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1


Hint: available channel list could be extracted by running the following
Hint: available channel list could be extracted by running the following
command:
command:
	% ls -1 /sys/class/dma/
	% ls -1 /sys/class/dma/


After a while you will start to get messages about current status or error like
Once started a message like "dmatest: Started 1 threads using dma0chan0" is
in the original code.
emitted.  After that only test failure messages are reported until the test
stops.


Note that running a new test will not stop any in progress test.
Note that running a new test will not stop any in progress test.


The following command should return actual state of the test.
The following command returns the state of the test.
	% cat /sys/kernel/debug/dmatest/run
	% cat /sys/module/dmatest/parameters/run


To wait for test done the user may perform a busy loop that checks the state.
To wait for test completion userpace can poll 'run' until it is false, or use

the wait parameter.  Specifying 'wait=1' when loading the module causes module
	% while [ $(cat /sys/kernel/debug/dmatest/run) = "Y" ]
initialization to pause until a test run has completed, while reading
	> do
/sys/module/dmatest/parameters/wait waits for any running test to complete
	> 	echo -n "."
before returning.  For example, the following scripts wait for 42 tests
	> 	sleep 1
to complete before exiting.  Note that if 'iterations' is set to 'infinite' then
	> done
waiting is disabled.
	> echo

Example:
	% modprobe dmatest run=1 iterations=42 wait=1
	% modprobe -r dmatest
...or:
	% modprobe dmatest run=1 iterations=42
	% cat /sys/module/dmatest/parameters/wait
	% modprobe -r dmatest


	Part 3 - When built-in in the kernel...
	Part 3 - When built-in in the kernel...


@@ -62,21 +71,22 @@ case. You always could check them at run-time by running


	Part 4 - Gathering the test results
	Part 4 - Gathering the test results


The module provides a storage for the test results in the memory. The gathered
Test results are printed to the kernel log buffer with the format:
data could be used after test is done.


The special file 'results' in the debugfs represents gathered data of the in
"dmatest: result <channel>: <test id>: '<error msg>' with src_off=<val> dst_off=<val> len=<val> (<err code>)"
progress test. The messages collected are printed to the kernel log as well.


Example of output:
Example of output:
	% cat /sys/kernel/debug/dmatest/results
	% dmesg | tail -n 1
	dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0)
	dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0)


The message format is unified across the different types of errors. A number in
The message format is unified across the different types of errors. A number in
the parens represents additional information, e.g. error code, error counter,
the parens represents additional information, e.g. error code, error counter,
or status.
or status.  A test thread also emits a summary line at completion listing the
number of tests executed, number that failed, and a result code.


Comparison between buffers is stored to the dedicated structure.
Example:
	% dmesg | tail -n 1
	dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0)


Note that the verify result is now accessible only via file 'results' in the
The details of a data miscompare error are also emitted, but do not follow the
debugfs.
above format.
+0 −30
Original line number Original line Diff line number Diff line
@@ -393,36 +393,6 @@ static inline int iop_chan_zero_sum_slot_count(size_t len, int src_cnt,
	return slot_cnt;
	return slot_cnt;
}
}


static inline int iop_desc_is_pq(struct iop_adma_desc_slot *desc)
{
	return 0;
}

static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc,
					struct iop_adma_chan *chan)
{
	union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };

	switch (chan->device->id) {
	case DMA0_ID:
	case DMA1_ID:
		return hw_desc.dma->dest_addr;
	case AAU_ID:
		return hw_desc.aau->dest_addr;
	default:
		BUG();
	}
	return 0;
}


static inline u32 iop_desc_get_qdest_addr(struct iop_adma_desc_slot *desc,
					  struct iop_adma_chan *chan)
{
	BUG();
	return 0;
}

static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc,
static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc,
					struct iop_adma_chan *chan)
					struct iop_adma_chan *chan)
{
{
+0 −4
Original line number Original line Diff line number Diff line
@@ -82,8 +82,6 @@ struct iop_adma_chan {
 * @slot_cnt: total slots used in an transaction (group of operations)
 * @slot_cnt: total slots used in an transaction (group of operations)
 * @slots_per_op: number of slots per operation
 * @slots_per_op: number of slots per operation
 * @idx: pool index
 * @idx: pool index
 * @unmap_src_cnt: number of xor sources
 * @unmap_len: transaction bytecount
 * @tx_list: list of descriptors that are associated with one operation
 * @tx_list: list of descriptors that are associated with one operation
 * @async_tx: support for the async_tx api
 * @async_tx: support for the async_tx api
 * @group_list: list of slots that make up a multi-descriptor transaction
 * @group_list: list of slots that make up a multi-descriptor transaction
@@ -99,8 +97,6 @@ struct iop_adma_desc_slot {
	u16 slot_cnt;
	u16 slot_cnt;
	u16 slots_per_op;
	u16 slots_per_op;
	u16 idx;
	u16 idx;
	u16 unmap_src_cnt;
	size_t unmap_len;
	struct list_head tx_list;
	struct list_head tx_list;
	struct dma_async_tx_descriptor async_tx;
	struct dma_async_tx_descriptor async_tx;
	union {
	union {
+0 −26
Original line number Original line Diff line number Diff line
@@ -218,20 +218,6 @@ iop_chan_xor_slot_count(size_t len, int src_cnt, int *slots_per_op)
#define iop_chan_pq_slot_count iop_chan_xor_slot_count
#define iop_chan_pq_slot_count iop_chan_xor_slot_count
#define iop_chan_pq_zero_sum_slot_count iop_chan_xor_slot_count
#define iop_chan_pq_zero_sum_slot_count iop_chan_xor_slot_count


static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc,
					struct iop_adma_chan *chan)
{
	struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
	return hw_desc->dest_addr;
}

static inline u32 iop_desc_get_qdest_addr(struct iop_adma_desc_slot *desc,
					  struct iop_adma_chan *chan)
{
	struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
	return hw_desc->q_dest_addr;
}

static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc,
static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc,
					struct iop_adma_chan *chan)
					struct iop_adma_chan *chan)
{
{
@@ -350,18 +336,6 @@ iop_desc_init_pq(struct iop_adma_desc_slot *desc, int src_cnt,
	hw_desc->desc_ctrl = u_desc_ctrl.value;
	hw_desc->desc_ctrl = u_desc_ctrl.value;
}
}


static inline int iop_desc_is_pq(struct iop_adma_desc_slot *desc)
{
	struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
	union {
		u32 value;
		struct iop13xx_adma_desc_ctrl field;
	} u_desc_ctrl;

	u_desc_ctrl.value = hw_desc->desc_ctrl;
	return u_desc_ctrl.field.pq_xfer_en;
}

static inline void
static inline void
iop_desc_init_pq_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
iop_desc_init_pq_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
			  unsigned long flags)
			  unsigned long flags)
+21 −16
Original line number Original line Diff line number Diff line
@@ -50,33 +50,36 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
						      &dest, 1, &src, 1, len);
						      &dest, 1, &src, 1, len);
	struct dma_device *device = chan ? chan->device : NULL;
	struct dma_device *device = chan ? chan->device : NULL;
	struct dma_async_tx_descriptor *tx = NULL;
	struct dma_async_tx_descriptor *tx = NULL;
	struct dmaengine_unmap_data *unmap = NULL;


	if (device && is_dma_copy_aligned(device, src_offset, dest_offset, len)) {
	if (device)
		dma_addr_t dma_dest, dma_src;
		unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOIO);

	if (unmap && is_dma_copy_aligned(device, src_offset, dest_offset, len)) {
		unsigned long dma_prep_flags = 0;
		unsigned long dma_prep_flags = 0;


		if (submit->cb_fn)
		if (submit->cb_fn)
			dma_prep_flags |= DMA_PREP_INTERRUPT;
			dma_prep_flags |= DMA_PREP_INTERRUPT;
		if (submit->flags & ASYNC_TX_FENCE)
		if (submit->flags & ASYNC_TX_FENCE)
			dma_prep_flags |= DMA_PREP_FENCE;
			dma_prep_flags |= DMA_PREP_FENCE;
		dma_dest = dma_map_page(device->dev, dest, dest_offset, len,
					DMA_FROM_DEVICE);


		dma_src = dma_map_page(device->dev, src, src_offset, len,
		unmap->to_cnt = 1;
		unmap->addr[0] = dma_map_page(device->dev, src, src_offset, len,
					      DMA_TO_DEVICE);
					      DMA_TO_DEVICE);

		unmap->from_cnt = 1;
		tx = device->device_prep_dma_memcpy(chan, dma_dest, dma_src,
		unmap->addr[1] = dma_map_page(device->dev, dest, dest_offset, len,
						    len, dma_prep_flags);
		if (!tx) {
			dma_unmap_page(device->dev, dma_dest, len,
					      DMA_FROM_DEVICE);
					      DMA_FROM_DEVICE);
			dma_unmap_page(device->dev, dma_src, len,
		unmap->len = len;
				       DMA_TO_DEVICE);

		}
		tx = device->device_prep_dma_memcpy(chan, unmap->addr[1],
						    unmap->addr[0], len,
						    dma_prep_flags);
	}
	}


	if (tx) {
	if (tx) {
		pr_debug("%s: (async) len: %zu\n", __func__, len);
		pr_debug("%s: (async) len: %zu\n", __func__, len);

		dma_set_unmap(tx, unmap);
		async_tx_submit(chan, tx, submit);
		async_tx_submit(chan, tx, submit);
	} else {
	} else {
		void *dest_buf, *src_buf;
		void *dest_buf, *src_buf;
@@ -96,6 +99,8 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
		async_tx_sync_epilog(submit);
		async_tx_sync_epilog(submit);
	}
	}


	dmaengine_unmap_put(unmap);

	return tx;
	return tx;
}
}
EXPORT_SYMBOL_GPL(async_memcpy);
EXPORT_SYMBOL_GPL(async_memcpy);
Loading