Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
466e601a
Commit
466e601a
authored
Dec 31, 2018
by
Vinod Koul
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/dmatest' into for-linus
parents
77ee1aac
f80f9988
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
349 additions
and
59 deletions
+349
-59
Documentation/driver-api/dmaengine/dmatest.rst
Documentation/driver-api/dmaengine/dmatest.rst
+103
-6
drivers/dma/dmatest.c
drivers/dma/dmatest.c
+246
-53
No files found.
Documentation/driver-api/dmaengine/dmatest.rst
View file @
466e601a
...
@@ -26,28 +26,43 @@ Part 2 - When dmatest is built as a module
...
@@ -26,28 +26,43 @@ Part 2 - When dmatest is built as a module
Example of usage::
Example of usage::
% modprobe dmatest
channel=dma0chan0 timeout=2000 iterations=1
run=1
% modprobe dmatest
timeout=2000 iterations=1 channel=dma0chan0
run=1
...or::
...or::
% modprobe dmatest
% modprobe dmatest
% 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 dma0chan0 > /sys/module/dmatest/parameters/channel
% echo 1 > /sys/module/dmatest/parameters/run
% echo 1 > /sys/module/dmatest/parameters/run
...or on the kernel command line::
...or on the kernel command line::
dmatest.channel=dma0chan0 dmatest.timeout=2000 dmatest.iterations=1 dmatest.run=1
dmatest.timeout=2000 dmatest.iterations=1 dmatest.channel=dma0chan0 dmatest.run=1
Example of multi-channel test usage:
% modprobe dmatest
% echo 2000 > /sys/module/dmatest/parameters/timeout
% echo 1 > /sys/module/dmatest/parameters/iterations
% echo dma0chan0 > /sys/module/dmatest/parameters/channel
% echo dma0chan1 > /sys/module/dmatest/parameters/channel
% echo dma0chan2 > /sys/module/dmatest/parameters/channel
% echo 1 > /sys/module/dmatest/parameters/run
Note: the channel parameter should always be the last parameter set prior to
running the test (setting run=1), this is because upon setting the channel
parameter, that specific channel is requested using the dmaengine and a thread
is created with the existing parameters. This thread is set as pending
and will be executed once run is set to 1. Any parameters set after the thread
is created are not applied.
.. hint::
.. hint::
available channel list could be extracted by running the following command::
available channel list could be extracted by running the following command::
% ls -1 /sys/class/dma/
% ls -1 /sys/class/dma/
Once started a message like "
dmatest: Start
ed 1 threads using dma0chan0" is
Once started a message like "
dmatest: Add
ed 1 threads using dma0chan0" is
emitted. A
fter that only test failure messages are reported until the test
emitted. A
thread for that specific channel is created and is now pending, the
stops
.
pending thread is started once run is to 1
.
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.
...
@@ -112,3 +127,85 @@ Example::
...
@@ -112,3 +127,85 @@ Example::
The details of a data miscompare error are also emitted, but do not follow the
The details of a data miscompare error are also emitted, but do not follow the
above format.
above format.
Part 5 - Handling channel allocation
====================================
Allocating Channels
-------------------
Channels are required to be configured prior to starting the test run.
Attempting to run the test without configuring the channels will fail.
Example::
% echo 1 > /sys/module/dmatest/parameters/run
dmatest: Could not start test, no channels configured
Channels are registered using the "channel" parameter. Channels can be requested by their
name, once requested, the channel is registered and a pending thread is added to the test list.
Example::
% echo dma0chan2 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan2
More channels can be added by repeating the example above.
Reading back the channel parameter will return the name of last channel that was added successfully.
Example::
% echo dma0chan1 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan1
% echo dma0chan2 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan2
% cat /sys/module/dmatest/parameters/channel
dma0chan2
Another method of requesting channels is to request a channel with an empty string, Doing so
will request all channels available to be tested:
Example::
% echo "" > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan0
dmatest: Added 1 threads using dma0chan3
dmatest: Added 1 threads using dma0chan4
dmatest: Added 1 threads using dma0chan5
dmatest: Added 1 threads using dma0chan6
dmatest: Added 1 threads using dma0chan7
dmatest: Added 1 threads using dma0chan8
At any point during the test configuration, reading the "test_list" parameter will
print the list of currently pending tests.
Example::
% cat /sys/module/dmatest/parameters/test_list
dmatest: 1 threads using dma0chan0
dmatest: 1 threads using dma0chan3
dmatest: 1 threads using dma0chan4
dmatest: 1 threads using dma0chan5
dmatest: 1 threads using dma0chan6
dmatest: 1 threads using dma0chan7
dmatest: 1 threads using dma0chan8
Note: Channels will have to be configured for each test run as channel configurations do not
carry across to the next test run.
Releasing Channels
-------------------
Channels can be freed by setting run to 0.
Example::
% echo dma0chan1 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan1
% cat /sys/class/dma/dma0chan1/in_use
1
% echo 0 > /sys/module/dmatest/parameters/run
% cat /sys/class/dma/dma0chan1/in_use
0
Channels allocated by previous test runs are automatically freed when a new
channel is requested after completing a successful test run.
drivers/dma/dmatest.c
View file @
466e601a
...
@@ -27,11 +27,6 @@ static unsigned int test_buf_size = 16384;
...
@@ -27,11 +27,6 @@ static unsigned int test_buf_size = 16384;
module_param
(
test_buf_size
,
uint
,
S_IRUGO
|
S_IWUSR
);
module_param
(
test_buf_size
,
uint
,
S_IRUGO
|
S_IWUSR
);
MODULE_PARM_DESC
(
test_buf_size
,
"Size of the memcpy test buffer"
);
MODULE_PARM_DESC
(
test_buf_size
,
"Size of the memcpy test buffer"
);
static
char
test_channel
[
20
];
module_param_string
(
channel
,
test_channel
,
sizeof
(
test_channel
),
S_IRUGO
|
S_IWUSR
);
MODULE_PARM_DESC
(
channel
,
"Bus ID of the channel to test (default: any)"
);
static
char
test_device
[
32
];
static
char
test_device
[
32
];
module_param_string
(
device
,
test_device
,
sizeof
(
test_device
),
module_param_string
(
device
,
test_device
,
sizeof
(
test_device
),
S_IRUGO
|
S_IWUSR
);
S_IRUGO
|
S_IWUSR
);
...
@@ -84,6 +79,14 @@ static bool verbose;
...
@@ -84,6 +79,14 @@ static bool verbose;
module_param
(
verbose
,
bool
,
S_IRUGO
|
S_IWUSR
);
module_param
(
verbose
,
bool
,
S_IRUGO
|
S_IWUSR
);
MODULE_PARM_DESC
(
verbose
,
"Enable
\"
success
\"
result messages (default: off)"
);
MODULE_PARM_DESC
(
verbose
,
"Enable
\"
success
\"
result messages (default: off)"
);
static
int
alignment
=
-
1
;
module_param
(
alignment
,
int
,
0644
);
MODULE_PARM_DESC
(
alignment
,
"Custom data address alignment taken as 2^(alignment) (default: not used (-1))"
);
static
unsigned
int
transfer_size
;
module_param
(
transfer_size
,
uint
,
0644
);
MODULE_PARM_DESC
(
transfer_size
,
"Optional custom transfer size in bytes (default: not used (0))"
);
/**
/**
* struct dmatest_params - test parameters.
* struct dmatest_params - test parameters.
* @buf_size: size of the memcpy test buffer
* @buf_size: size of the memcpy test buffer
...
@@ -108,6 +111,8 @@ struct dmatest_params {
...
@@ -108,6 +111,8 @@ struct dmatest_params {
int
timeout
;
int
timeout
;
bool
noverify
;
bool
noverify
;
bool
norandom
;
bool
norandom
;
int
alignment
;
unsigned
int
transfer_size
;
};
};
/**
/**
...
@@ -139,6 +144,28 @@ static bool dmatest_run;
...
@@ -139,6 +144,28 @@ static bool dmatest_run;
module_param_cb
(
run
,
&
run_ops
,
&
dmatest_run
,
S_IRUGO
|
S_IWUSR
);
module_param_cb
(
run
,
&
run_ops
,
&
dmatest_run
,
S_IRUGO
|
S_IWUSR
);
MODULE_PARM_DESC
(
run
,
"Run the test (default: false)"
);
MODULE_PARM_DESC
(
run
,
"Run the test (default: false)"
);
static
int
dmatest_chan_set
(
const
char
*
val
,
const
struct
kernel_param
*
kp
);
static
int
dmatest_chan_get
(
char
*
val
,
const
struct
kernel_param
*
kp
);
static
const
struct
kernel_param_ops
multi_chan_ops
=
{
.
set
=
dmatest_chan_set
,
.
get
=
dmatest_chan_get
,
};
static
char
test_channel
[
20
];
static
struct
kparam_string
newchan_kps
=
{
.
string
=
test_channel
,
.
maxlen
=
20
,
};
module_param_cb
(
channel
,
&
multi_chan_ops
,
&
newchan_kps
,
0644
);
MODULE_PARM_DESC
(
channel
,
"Bus ID of the channel to test (default: any)"
);
static
int
dmatest_test_list_get
(
char
*
val
,
const
struct
kernel_param
*
kp
);
static
const
struct
kernel_param_ops
test_list_ops
=
{
.
get
=
dmatest_test_list_get
,
};
module_param_cb
(
test_list
,
&
test_list_ops
,
NULL
,
0444
);
MODULE_PARM_DESC
(
test_list
,
"Print current test list"
);
/* Maximum amount of mismatched bytes in buffer to print */
/* Maximum amount of mismatched bytes in buffer to print */
#define MAX_ERROR_COUNT 32
#define MAX_ERROR_COUNT 32
...
@@ -160,6 +187,13 @@ MODULE_PARM_DESC(run, "Run the test (default: false)");
...
@@ -160,6 +187,13 @@ MODULE_PARM_DESC(run, "Run the test (default: false)");
#define PATTERN_COUNT_MASK 0x1f
#define PATTERN_COUNT_MASK 0x1f
#define PATTERN_MEMSET_IDX 0x01
#define PATTERN_MEMSET_IDX 0x01
/* Fixed point arithmetic ops */
#define FIXPT_SHIFT 8
#define FIXPNT_MASK 0xFF
#define FIXPT_TO_INT(a) ((a) >> FIXPT_SHIFT)
#define INT_TO_FIXPT(a) ((a) << FIXPT_SHIFT)
#define FIXPT_GET_FRAC(a) ((((a) & FIXPNT_MASK) * 100) >> FIXPT_SHIFT)
/* poor man's completion - we want to use wait_event_freezable() on it */
/* poor man's completion - we want to use wait_event_freezable() on it */
struct
dmatest_done
{
struct
dmatest_done
{
bool
done
;
bool
done
;
...
@@ -179,6 +213,7 @@ struct dmatest_thread {
...
@@ -179,6 +213,7 @@ struct dmatest_thread {
wait_queue_head_t
done_wait
;
wait_queue_head_t
done_wait
;
struct
dmatest_done
test_done
;
struct
dmatest_done
test_done
;
bool
done
;
bool
done
;
bool
pending
;
};
};
struct
dmatest_chan
{
struct
dmatest_chan
{
...
@@ -206,6 +241,22 @@ static bool is_threaded_test_run(struct dmatest_info *info)
...
@@ -206,6 +241,22 @@ static bool is_threaded_test_run(struct dmatest_info *info)
return
false
;
return
false
;
}
}
static
bool
is_threaded_test_pending
(
struct
dmatest_info
*
info
)
{
struct
dmatest_chan
*
dtc
;
list_for_each_entry
(
dtc
,
&
info
->
channels
,
node
)
{
struct
dmatest_thread
*
thread
;
list_for_each_entry
(
thread
,
&
dtc
->
threads
,
node
)
{
if
(
thread
->
pending
)
return
true
;
}
}
return
false
;
}
static
int
dmatest_wait_get
(
char
*
val
,
const
struct
kernel_param
*
kp
)
static
int
dmatest_wait_get
(
char
*
val
,
const
struct
kernel_param
*
kp
)
{
{
struct
dmatest_info
*
info
=
&
test_info
;
struct
dmatest_info
*
info
=
&
test_info
;
...
@@ -419,13 +470,15 @@ static unsigned long long dmatest_persec(s64 runtime, unsigned int val)
...
@@ -419,13 +470,15 @@ static unsigned long long dmatest_persec(s64 runtime, unsigned int val)
}
}
per_sec
*=
val
;
per_sec
*=
val
;
per_sec
=
INT_TO_FIXPT
(
per_sec
);
do_div
(
per_sec
,
runtime
);
do_div
(
per_sec
,
runtime
);
return
per_sec
;
return
per_sec
;
}
}
static
unsigned
long
long
dmatest_KBs
(
s64
runtime
,
unsigned
long
long
len
)
static
unsigned
long
long
dmatest_KBs
(
s64
runtime
,
unsigned
long
long
len
)
{
{
return
dmatest_persec
(
runtime
,
len
>>
10
);
return
FIXPT_TO_INT
(
dmatest_persec
(
runtime
,
len
>>
10
)
);
}
}
/*
/*
...
@@ -466,6 +519,7 @@ static int dmatest_func(void *data)
...
@@ -466,6 +519,7 @@ static int dmatest_func(void *data)
ktime_t
comparetime
=
0
;
ktime_t
comparetime
=
0
;
s64
runtime
=
0
;
s64
runtime
=
0
;
unsigned
long
long
total_len
=
0
;
unsigned
long
long
total_len
=
0
;
unsigned
long
long
iops
=
0
;
u8
align
=
0
;
u8
align
=
0
;
bool
is_memset
=
false
;
bool
is_memset
=
false
;
dma_addr_t
*
srcs
;
dma_addr_t
*
srcs
;
...
@@ -476,27 +530,32 @@ static int dmatest_func(void *data)
...
@@ -476,27 +530,32 @@ static int dmatest_func(void *data)
ret
=
-
ENOMEM
;
ret
=
-
ENOMEM
;
smp_rmb
();
smp_rmb
();
thread
->
pending
=
false
;
info
=
thread
->
info
;
info
=
thread
->
info
;
params
=
&
info
->
params
;
params
=
&
info
->
params
;
chan
=
thread
->
chan
;
chan
=
thread
->
chan
;
dev
=
chan
->
device
;
dev
=
chan
->
device
;
if
(
thread
->
type
==
DMA_MEMCPY
)
{
if
(
thread
->
type
==
DMA_MEMCPY
)
{
align
=
dev
->
copy_align
;
align
=
params
->
alignment
<
0
?
dev
->
copy_align
:
params
->
alignment
;
src_cnt
=
dst_cnt
=
1
;
src_cnt
=
dst_cnt
=
1
;
}
else
if
(
thread
->
type
==
DMA_MEMSET
)
{
}
else
if
(
thread
->
type
==
DMA_MEMSET
)
{
align
=
dev
->
fill_align
;
align
=
params
->
alignment
<
0
?
dev
->
fill_align
:
params
->
alignment
;
src_cnt
=
dst_cnt
=
1
;
src_cnt
=
dst_cnt
=
1
;
is_memset
=
true
;
is_memset
=
true
;
}
else
if
(
thread
->
type
==
DMA_XOR
)
{
}
else
if
(
thread
->
type
==
DMA_XOR
)
{
/* force odd to ensure dst = src */
/* force odd to ensure dst = src */
src_cnt
=
min_odd
(
params
->
xor_sources
|
1
,
dev
->
max_xor
);
src_cnt
=
min_odd
(
params
->
xor_sources
|
1
,
dev
->
max_xor
);
dst_cnt
=
1
;
dst_cnt
=
1
;
align
=
dev
->
xor_align
;
align
=
params
->
alignment
<
0
?
dev
->
xor_align
:
params
->
alignment
;
}
else
if
(
thread
->
type
==
DMA_PQ
)
{
}
else
if
(
thread
->
type
==
DMA_PQ
)
{
/* force odd to ensure dst = src */
/* force odd to ensure dst = src */
src_cnt
=
min_odd
(
params
->
pq_sources
|
1
,
dma_maxpq
(
dev
,
0
));
src_cnt
=
min_odd
(
params
->
pq_sources
|
1
,
dma_maxpq
(
dev
,
0
));
dst_cnt
=
2
;
dst_cnt
=
2
;
align
=
dev
->
pq_align
;
align
=
params
->
alignment
<
0
?
dev
->
pq_align
:
params
->
alignment
;
pq_coefs
=
kmalloc
(
params
->
pq_sources
+
1
,
GFP_KERNEL
);
pq_coefs
=
kmalloc
(
params
->
pq_sources
+
1
,
GFP_KERNEL
);
if
(
!
pq_coefs
)
if
(
!
pq_coefs
)
...
@@ -507,9 +566,22 @@ static int dmatest_func(void *data)
...
@@ -507,9 +566,22 @@ static int dmatest_func(void *data)
}
else
}
else
goto
err_thread_type
;
goto
err_thread_type
;
/* Check if buffer count fits into map count variable (u8) */
if
((
src_cnt
+
dst_cnt
)
>=
255
)
{
pr_err
(
"too many buffers (%d of 255 supported)
\n
"
,
src_cnt
+
dst_cnt
);
goto
err_free_coefs
;
}
if
(
1
<<
align
>
params
->
buf_size
)
{
pr_err
(
"%u-byte buffer too small for %d-byte alignment
\n
"
,
params
->
buf_size
,
1
<<
align
);
goto
err_free_coefs
;
}
thread
->
srcs
=
kcalloc
(
src_cnt
+
1
,
sizeof
(
u8
*
),
GFP_KERNEL
);
thread
->
srcs
=
kcalloc
(
src_cnt
+
1
,
sizeof
(
u8
*
),
GFP_KERNEL
);
if
(
!
thread
->
srcs
)
if
(
!
thread
->
srcs
)
goto
err_
src
s
;
goto
err_
free_coef
s
;
thread
->
usrcs
=
kcalloc
(
src_cnt
+
1
,
sizeof
(
u8
*
),
GFP_KERNEL
);
thread
->
usrcs
=
kcalloc
(
src_cnt
+
1
,
sizeof
(
u8
*
),
GFP_KERNEL
);
if
(
!
thread
->
usrcs
)
if
(
!
thread
->
usrcs
)
...
@@ -576,28 +648,25 @@ static int dmatest_func(void *data)
...
@@ -576,28 +648,25 @@ static int dmatest_func(void *data)
total_tests
++
;
total_tests
++
;
/* Check if buffer count fits into map count variable (u8) */
if
(
params
->
transfer_size
)
{
if
((
src_cnt
+
dst_cnt
)
>=
255
)
{
if
(
params
->
transfer_size
>=
params
->
buf_size
)
{
pr_err
(
"too many buffers (%d of 255 supported)
\n
"
,
pr_err
(
"%u-byte transfer size must be lower than %u-buffer size
\n
"
,
src_cnt
+
dst_cnt
);
params
->
transfer_size
,
params
->
buf_size
);
break
;
break
;
}
}
len
=
params
->
transfer_size
;
if
(
1
<<
align
>
params
->
buf_size
)
{
}
else
if
(
params
->
norandom
)
{
pr_err
(
"%u-byte buffer too small for %d-byte alignment
\n
"
,
params
->
buf_size
,
1
<<
align
);
break
;
}
if
(
params
->
norandom
)
len
=
params
->
buf_size
;
len
=
params
->
buf_size
;
else
}
else
{
len
=
dmatest_random
()
%
params
->
buf_size
+
1
;
len
=
dmatest_random
()
%
params
->
buf_size
+
1
;
}
len
=
(
len
>>
align
)
<<
align
;
/* Do not alter transfer size explicitly defined by user */
if
(
!
len
)
if
(
!
params
->
transfer_size
)
{
len
=
1
<<
align
;
len
=
(
len
>>
align
)
<<
align
;
if
(
!
len
)
len
=
1
<<
align
;
}
total_len
+=
len
;
total_len
+=
len
;
if
(
params
->
norandom
)
{
if
(
params
->
norandom
)
{
...
@@ -721,14 +790,14 @@ static int dmatest_func(void *data)
...
@@ -721,14 +790,14 @@ static int dmatest_func(void *data)
status
=
dma_async_is_tx_complete
(
chan
,
cookie
,
NULL
,
NULL
);
status
=
dma_async_is_tx_complete
(
chan
,
cookie
,
NULL
,
NULL
);
dmaengine_unmap_put
(
um
);
if
(
!
done
->
done
)
{
if
(
!
done
->
done
)
{
dmaengine_unmap_put
(
um
);
result
(
"test timed out"
,
total_tests
,
src_off
,
dst_off
,
result
(
"test timed out"
,
total_tests
,
src_off
,
dst_off
,
len
,
0
);
len
,
0
);
failed_tests
++
;
failed_tests
++
;
continue
;
continue
;
}
else
if
(
status
!=
DMA_COMPLETE
)
{
}
else
if
(
status
!=
DMA_COMPLETE
)
{
dmaengine_unmap_put
(
um
);
result
(
status
==
DMA_ERROR
?
result
(
status
==
DMA_ERROR
?
"completion error status"
:
"completion error status"
:
"completion busy status"
,
total_tests
,
src_off
,
"completion busy status"
,
total_tests
,
src_off
,
...
@@ -737,8 +806,6 @@ static int dmatest_func(void *data)
...
@@ -737,8 +806,6 @@ static int dmatest_func(void *data)
continue
;
continue
;
}
}
dmaengine_unmap_put
(
um
);
if
(
params
->
noverify
)
{
if
(
params
->
noverify
)
{
verbose_result
(
"test passed"
,
total_tests
,
src_off
,
verbose_result
(
"test passed"
,
total_tests
,
src_off
,
dst_off
,
len
,
0
);
dst_off
,
len
,
0
);
...
@@ -802,17 +869,18 @@ static int dmatest_func(void *data)
...
@@ -802,17 +869,18 @@ static int dmatest_func(void *data)
kfree
(
thread
->
usrcs
);
kfree
(
thread
->
usrcs
);
err_usrcs:
err_usrcs:
kfree
(
thread
->
srcs
);
kfree
(
thread
->
srcs
);
err_
src
s:
err_
free_coef
s:
kfree
(
pq_coefs
);
kfree
(
pq_coefs
);
err_thread_type:
err_thread_type:
pr_info
(
"%s: summary %u tests, %u failures %llu iops %llu KB/s (%d)
\n
"
,
iops
=
dmatest_persec
(
runtime
,
total_tests
);
pr_info
(
"%s: summary %u tests, %u failures %llu.%02llu iops %llu KB/s (%d)
\n
"
,
current
->
comm
,
total_tests
,
failed_tests
,
current
->
comm
,
total_tests
,
failed_tests
,
dmatest_persec
(
runtime
,
total_test
s
),
FIXPT_TO_INT
(
iops
),
FIXPT_GET_FRAC
(
iop
s
),
dmatest_KBs
(
runtime
,
total_len
),
ret
);
dmatest_KBs
(
runtime
,
total_len
),
ret
);
/* terminate all transfers on specified channels */
/* terminate all transfers on specified channels */
if
(
ret
||
failed_tests
)
if
(
ret
||
failed_tests
)
dmaengine_terminate_
all
(
chan
);
dmaengine_terminate_
sync
(
chan
);
thread
->
done
=
true
;
thread
->
done
=
true
;
wake_up
(
&
thread_wait
);
wake_up
(
&
thread_wait
);
...
@@ -836,7 +904,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc)
...
@@ -836,7 +904,7 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc)
}
}
/* terminate all transfers on specified channels */
/* terminate all transfers on specified channels */
dmaengine_terminate_
all
(
dtc
->
chan
);
dmaengine_terminate_
sync
(
dtc
->
chan
);
kfree
(
dtc
);
kfree
(
dtc
);
}
}
...
@@ -886,7 +954,7 @@ static int dmatest_add_threads(struct dmatest_info *info,
...
@@ -886,7 +954,7 @@ static int dmatest_add_threads(struct dmatest_info *info,
/* srcbuf and dstbuf are allocated by the thread itself */
/* srcbuf and dstbuf are allocated by the thread itself */
get_task_struct
(
thread
->
task
);
get_task_struct
(
thread
->
task
);
list_add_tail
(
&
thread
->
node
,
&
dtc
->
threads
);
list_add_tail
(
&
thread
->
node
,
&
dtc
->
threads
);
wake_up_process
(
thread
->
task
)
;
thread
->
pending
=
true
;
}
}
return
i
;
return
i
;
...
@@ -932,7 +1000,7 @@ static int dmatest_add_channel(struct dmatest_info *info,
...
@@ -932,7 +1000,7 @@ static int dmatest_add_channel(struct dmatest_info *info,
thread_count
+=
cnt
>
0
?
cnt
:
0
;
thread_count
+=
cnt
>
0
?
cnt
:
0
;
}
}
pr_info
(
"
Start
ed %u threads using %s
\n
"
,
pr_info
(
"
Add
ed %u threads using %s
\n
"
,
thread_count
,
dma_chan_name
(
chan
));
thread_count
,
dma_chan_name
(
chan
));
list_add_tail
(
&
dtc
->
node
,
&
info
->
channels
);
list_add_tail
(
&
dtc
->
node
,
&
info
->
channels
);
...
@@ -977,7 +1045,7 @@ static void request_channels(struct dmatest_info *info,
...
@@ -977,7 +1045,7 @@ static void request_channels(struct dmatest_info *info,
}
}
}
}
static
void
run
_threaded_test
(
struct
dmatest_info
*
info
)
static
void
add
_threaded_test
(
struct
dmatest_info
*
info
)
{
{
struct
dmatest_params
*
params
=
&
info
->
params
;
struct
dmatest_params
*
params
=
&
info
->
params
;
...
@@ -993,6 +1061,8 @@ static void run_threaded_test(struct dmatest_info *info)
...
@@ -993,6 +1061,8 @@ static void run_threaded_test(struct dmatest_info *info)
params
->
timeout
=
timeout
;
params
->
timeout
=
timeout
;
params
->
noverify
=
noverify
;
params
->
noverify
=
noverify
;
params
->
norandom
=
norandom
;
params
->
norandom
=
norandom
;
params
->
alignment
=
alignment
;
params
->
transfer_size
=
transfer_size
;
request_channels
(
info
,
DMA_MEMCPY
);
request_channels
(
info
,
DMA_MEMCPY
);
request_channels
(
info
,
DMA_MEMSET
);
request_channels
(
info
,
DMA_MEMSET
);
...
@@ -1000,6 +1070,24 @@ static void run_threaded_test(struct dmatest_info *info)
...
@@ -1000,6 +1070,24 @@ static void run_threaded_test(struct dmatest_info *info)
request_channels
(
info
,
DMA_PQ
);
request_channels
(
info
,
DMA_PQ
);
}
}
static
void
run_pending_tests
(
struct
dmatest_info
*
info
)
{
struct
dmatest_chan
*
dtc
;
unsigned
int
thread_count
=
0
;
list_for_each_entry
(
dtc
,
&
info
->
channels
,
node
)
{
struct
dmatest_thread
*
thread
;
thread_count
=
0
;
list_for_each_entry
(
thread
,
&
dtc
->
threads
,
node
)
{
wake_up_process
(
thread
->
task
);
thread_count
++
;
}
pr_info
(
"Started %u threads using %s
\n
"
,
thread_count
,
dma_chan_name
(
dtc
->
chan
));
}
}
static
void
stop_threaded_test
(
struct
dmatest_info
*
info
)
static
void
stop_threaded_test
(
struct
dmatest_info
*
info
)
{
{
struct
dmatest_chan
*
dtc
,
*
_dtc
;
struct
dmatest_chan
*
dtc
,
*
_dtc
;
...
@@ -1016,7 +1104,7 @@ static void stop_threaded_test(struct dmatest_info *info)
...
@@ -1016,7 +1104,7 @@ static void stop_threaded_test(struct dmatest_info *info)
info
->
nr_channels
=
0
;
info
->
nr_channels
=
0
;
}
}
static
void
restart_threaded_test
(
struct
dmatest_info
*
info
,
bool
run
)
static
void
start_threaded_tests
(
struct
dmatest_info
*
info
)
{
{
/* we might be called early to set run=, defer running until all
/* we might be called early to set run=, defer running until all
* parameters have been evaluated
* parameters have been evaluated
...
@@ -1024,11 +1112,7 @@ static void restart_threaded_test(struct dmatest_info *info, bool run)
...
@@ -1024,11 +1112,7 @@ static void restart_threaded_test(struct dmatest_info *info, bool run)
if
(
!
info
->
did_init
)
if
(
!
info
->
did_init
)
return
;
return
;
/* Stop any running test first */
run_pending_tests
(
info
);
stop_threaded_test
(
info
);
/* Run test with new parameters */
run_threaded_test
(
info
);
}
}
static
int
dmatest_run_get
(
char
*
val
,
const
struct
kernel_param
*
kp
)
static
int
dmatest_run_get
(
char
*
val
,
const
struct
kernel_param
*
kp
)
...
@@ -1039,7 +1123,8 @@ static int dmatest_run_get(char *val, const struct kernel_param *kp)
...
@@ -1039,7 +1123,8 @@ static int dmatest_run_get(char *val, const struct kernel_param *kp)
if
(
is_threaded_test_run
(
info
))
{
if
(
is_threaded_test_run
(
info
))
{
dmatest_run
=
true
;
dmatest_run
=
true
;
}
else
{
}
else
{
stop_threaded_test
(
info
);
if
(
!
is_threaded_test_pending
(
info
))
stop_threaded_test
(
info
);
dmatest_run
=
false
;
dmatest_run
=
false
;
}
}
mutex_unlock
(
&
info
->
lock
);
mutex_unlock
(
&
info
->
lock
);
...
@@ -1057,18 +1142,125 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp)
...
@@ -1057,18 +1142,125 @@ static int dmatest_run_set(const char *val, const struct kernel_param *kp)
if
(
ret
)
{
if
(
ret
)
{
mutex_unlock
(
&
info
->
lock
);
mutex_unlock
(
&
info
->
lock
);
return
ret
;
return
ret
;
}
else
if
(
dmatest_run
)
{
if
(
is_threaded_test_pending
(
info
))
start_threaded_tests
(
info
);
else
pr_info
(
"Could not start test, no channels configured
\n
"
);
}
else
{
stop_threaded_test
(
info
);
}
}
if
(
is_threaded_test_run
(
info
))
mutex_unlock
(
&
info
->
lock
);
return
ret
;
}
static
int
dmatest_chan_set
(
const
char
*
val
,
const
struct
kernel_param
*
kp
)
{
struct
dmatest_info
*
info
=
&
test_info
;
struct
dmatest_chan
*
dtc
;
char
chan_reset_val
[
20
];
int
ret
=
0
;
mutex_lock
(
&
info
->
lock
);
ret
=
param_set_copystring
(
val
,
kp
);
if
(
ret
)
{
mutex_unlock
(
&
info
->
lock
);
return
ret
;
}
/*Clear any previously run threads */
if
(
!
is_threaded_test_run
(
info
)
&&
!
is_threaded_test_pending
(
info
))
stop_threaded_test
(
info
);
/* Reject channels that are already registered */
if
(
is_threaded_test_pending
(
info
))
{
list_for_each_entry
(
dtc
,
&
info
->
channels
,
node
)
{
if
(
strcmp
(
dma_chan_name
(
dtc
->
chan
),
strim
(
test_channel
))
==
0
)
{
dtc
=
list_last_entry
(
&
info
->
channels
,
struct
dmatest_chan
,
node
);
strlcpy
(
chan_reset_val
,
dma_chan_name
(
dtc
->
chan
),
sizeof
(
chan_reset_val
));
ret
=
-
EBUSY
;
goto
add_chan_err
;
}
}
}
add_threaded_test
(
info
);
/* Check if channel was added successfully */
dtc
=
list_last_entry
(
&
info
->
channels
,
struct
dmatest_chan
,
node
);
if
(
dtc
->
chan
)
{
/*
* if new channel was not successfully added, revert the
* "test_channel" string to the name of the last successfully
* added channel. exception for when users issues empty string
* to channel parameter.
*/
if
((
strcmp
(
dma_chan_name
(
dtc
->
chan
),
strim
(
test_channel
))
!=
0
)
&&
(
strcmp
(
""
,
strim
(
test_channel
))
!=
0
))
{
ret
=
-
EINVAL
;
strlcpy
(
chan_reset_val
,
dma_chan_name
(
dtc
->
chan
),
sizeof
(
chan_reset_val
));
goto
add_chan_err
;
}
}
else
{
/* Clear test_channel if no channels were added successfully */
strlcpy
(
chan_reset_val
,
""
,
sizeof
(
chan_reset_val
));
ret
=
-
EBUSY
;
ret
=
-
EBUSY
;
else
if
(
dmatest_run
)
goto
add_chan_err
;
restart_threaded_test
(
info
,
dmatest_run
);
}
mutex_unlock
(
&
info
->
lock
);
return
ret
;
add_chan_err:
param_set_copystring
(
chan_reset_val
,
kp
);
mutex_unlock
(
&
info
->
lock
);
mutex_unlock
(
&
info
->
lock
);
return
ret
;
return
ret
;
}
}
static
int
dmatest_chan_get
(
char
*
val
,
const
struct
kernel_param
*
kp
)
{
struct
dmatest_info
*
info
=
&
test_info
;
mutex_lock
(
&
info
->
lock
);
if
(
!
is_threaded_test_run
(
info
)
&&
!
is_threaded_test_pending
(
info
))
{
stop_threaded_test
(
info
);
strlcpy
(
test_channel
,
""
,
sizeof
(
test_channel
));
}
mutex_unlock
(
&
info
->
lock
);
return
param_get_string
(
val
,
kp
);
}
static
int
dmatest_test_list_get
(
char
*
val
,
const
struct
kernel_param
*
kp
)
{
struct
dmatest_info
*
info
=
&
test_info
;
struct
dmatest_chan
*
dtc
;
unsigned
int
thread_count
=
0
;
list_for_each_entry
(
dtc
,
&
info
->
channels
,
node
)
{
struct
dmatest_thread
*
thread
;
thread_count
=
0
;
list_for_each_entry
(
thread
,
&
dtc
->
threads
,
node
)
{
thread_count
++
;
}
pr_info
(
"%u threads using %s
\n
"
,
thread_count
,
dma_chan_name
(
dtc
->
chan
));
}
return
0
;
}
static
int
__init
dmatest_init
(
void
)
static
int
__init
dmatest_init
(
void
)
{
{
struct
dmatest_info
*
info
=
&
test_info
;
struct
dmatest_info
*
info
=
&
test_info
;
...
@@ -1076,7 +1268,8 @@ static int __init dmatest_init(void)
...
@@ -1076,7 +1268,8 @@ static int __init dmatest_init(void)
if
(
dmatest_run
)
{
if
(
dmatest_run
)
{
mutex_lock
(
&
info
->
lock
);
mutex_lock
(
&
info
->
lock
);
run_threaded_test
(
info
);
add_threaded_test
(
info
);
run_pending_tests
(
info
);
mutex_unlock
(
&
info
->
lock
);
mutex_unlock
(
&
info
->
lock
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment