Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC TDC 1ns 5cha - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
FMC TDC 1ns 5cha - Software
Commits
b3f907e8
Commit
b3f907e8
authored
Aug 23, 2018
by
Federico Vaga
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drv: export testing DMA function to user-space
Signed-off-by:
Federico Vaga
<
federico.vaga@cern.ch
>
parent
954a5ad6
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
217 additions
and
48 deletions
+217
-48
fmc-tdc.h
kernel/fmc-tdc.h
+25
-3
ft-core.c
kernel/ft-core.c
+161
-27
ft-irq.c
kernel/ft-irq.c
+1
-1
ft-zio.c
kernel/ft-zio.c
+21
-16
gennum-dma.h
kernel/hw/gennum-dma.h
+9
-1
No files found.
kernel/fmc-tdc.h
View file @
b3f907e8
...
...
@@ -53,6 +53,8 @@ enum ft_zattr_in_idx {
enum
ft_zattr_paremeters
{
FT_ATTR_PARAM_TEMP
=
FT_ATTR_TDC__LAST
,
FT_ATTR_PARAM_DMA
,
FT_ATTR_PARAM_DMA_SG
,
};
enum
ft_command
{
...
...
@@ -294,6 +296,8 @@ void ft_irq_coalescing_timeout_set(struct fmctdc_dev *ft,
uint32_t
ft_irq_coalescing_timeout_get
(
struct
fmctdc_dev
*
ft
,
unsigned
int
chan
);
int
test_dma
(
struct
fmctdc_dev
*
ft
,
unsigned
int
buf_size
,
unsigned
int
use_sg
);
/**
* It enables the acquisition on a give channel
...
...
@@ -344,11 +348,29 @@ static inline void gn4124_dma_start(struct fmctdc_dev *ft)
/**
* It does an active wait until the DMA transfer is over
* @ft FmcTdc device instance
* @timeout_ms timeout in milli-seconds
*/
static
inline
void
gn4124_dma_wait_done
(
struct
fmctdc_dev
*
ft
)
static
inline
enum
gncore_dma_status
gn4124_dma_wait_done
(
struct
fmctdc_dev
*
ft
,
unsigned
int
timeout_ms
)
{
while
(
!
(
dma_readl
(
ft
,
GENNUM_DMA_STA
)
&
GENNUM_DMA_STA_DONE
))
uint32_t
tmp
;
unsigned
long
timeout
=
jiffies
+
msecs_to_jiffies
(
timeout_ms
);
while
(
1
)
{
tmp
=
dma_readl
(
ft
,
GENNUM_DMA_STA
)
&
GENUM_DMA_STA_MASK
;
switch
(
tmp
)
{
case
GENNUM_DMA_STA_DONE
:
case
GENNUM_DMA_STA_ERROR
:
case
GENNUM_DMA_STA_ABORT
:
return
tmp
;
default:
if
(
time_after
(
jiffies
,
timeout
))
gn4124_dma_abort
(
ft
);
cpu_relax
();
break
;
}
}
}
/**
...
...
kernel/ft-core.c
View file @
b3f907e8
...
...
@@ -307,7 +307,7 @@ void gn4124_dma_read(struct fmctdc_dev *ft, uint32_t devmem, void *hostmem, int
return
;
gn4124_dma_start
(
ft
);
gn4124_dma_wait_done
(
ft
);
gn4124_dma_wait_done
(
ft
,
10000
);
gn4124_dma_unmap
(
ft
,
dma_handle
,
len
);
}
...
...
@@ -337,57 +337,192 @@ void gn4124_dma_write(struct fmctdc_dev *ft, uint32_t dst, void *src, int len)
item
.
attribute
=
GENNUM_DMA_ATTR_DIR
;
gn4124_dma_config
(
ft
,
&
item
);
gn4124_dma_start
(
ft
);
gn4124_dma_wait_done
(
ft
);
gn4124_dma_wait_done
(
ft
,
10000
);
dma_sync_single_for_device
(
ft
->
fmc
->
hwdev
,
dma_handle
,
len
,
DMA_TO_DEVICE
);
dma_unmap_single
(
ft
->
fmc
->
hwdev
,
dma_handle
,
len
,
DMA_TO_DEVICE
);
}
#if 1
int
test_dma
(
struct
fmctdc_dev
*
ft
)
static
int
gn4124_dma_sg
(
struct
fmctdc_dev
*
ft
,
uint32_t
offset
,
void
*
buf
,
int
size
,
enum
dma_data_direction
dir
)
{
struct
gncore_dma_item
*
item
;
/* linked-list descriptor */
struct
sg_table
sgt
;
dma_addr_t
item_pool
;
/* DMA mem for linked-list descriptors */
dma_addr_t
item_dma
;
/* temporary pointer */
uint32_t
devmem
=
offset
;
struct
scatterlist
*
sg
;
enum
gncore_dma_status
status
;
int
mapbytes
=
0
;
int
byteleft
=
size
;
int
ret
;
int
n
=
(
size
/
PAGE_SIZE
)
+
(
size
%
PAGE_SIZE
?
1
:
0
);
int
i
;
item
=
kmalloc
(
sizeof
(
struct
gncore_dma_item
)
*
n
,
GFP_KERNEL
);
if
(
!
item
)
return
-
ENOMEM
;
item_pool
=
dma_map_single
(
ft
->
fmc
->
hwdev
,
item
,
sizeof
(
struct
gncore_dma_item
)
*
n
,
DMA_TO_DEVICE
);
if
(
dma_mapping_error
(
ft
->
fmc
->
hwdev
,
item_pool
))
{
ret
=
-
EINVAL
;
goto
out_dma_item
;
}
ret
=
sg_alloc_table
(
&
sgt
,
n
,
GFP_KERNEL
);
if
(
ret
)
{
ret
=
-
ENOMEM
;
goto
out_sg_alloc
;
}
for_each_sg
(
sgt
.
sgl
,
sg
,
sgt
.
nents
,
i
)
{
void
*
bufp
=
buf
+
mapbytes
;
if
(
byteleft
<
(
PAGE_SIZE
-
offset_in_page
(
bufp
)))
mapbytes
=
byteleft
;
else
mapbytes
=
PAGE_SIZE
-
offset_in_page
(
bufp
);
sg_set_buf
(
sg
,
buf
,
mapbytes
);
byteleft
-=
mapbytes
;
}
ret
=
dma_map_sg
(
ft
->
fmc
->
hwdev
,
sgt
.
sgl
,
sgt
.
nents
,
dir
);
if
(
ret
<
0
)
goto
out_map_sg
;
item_dma
=
item_pool
;
for_each_sg
(
sgt
.
sgl
,
sg
,
sgt
.
nents
,
i
)
{
item
[
i
].
start_addr
=
devmem
;
item
[
i
].
dma_addr_h
=
sg_dma_address
(
sg
)
>>
32
;
item
[
i
].
dma_addr_l
=
sg_dma_address
(
sg
)
&
0xFFFFFFFFULL
;
item
[
i
].
dma_len
=
sg_dma_len
(
sg
);
item
[
i
].
next_addr_h
=
item_dma
>>
32
;
item
[
i
].
next_addr_l
=
item_dma
&
0xFFFFFFFFULL
;
item
[
i
].
attribute
=
0
;
if
(
DMA_TO_DEVICE
)
item
[
i
].
attribute
=
GENNUM_DMA_ATTR_DIR
;
if
(
!
sg_is_last
(
sg
))
item
[
i
].
attribute
=
GENNUM_DMA_ATTR_MORE
;
item_dma
+=
sizeof
(
struct
gncore_dma_item
);
devmem
+=
sg_dma_len
(
sg
);
}
gn4124_dma_config
(
ft
,
&
item
[
0
]);
dma_sync_single_for_device
(
ft
->
fmc
->
hwdev
,
item_pool
,
sizeof
(
struct
gncore_dma_item
)
*
sgt
.
nents
,
DMA_TO_DEVICE
);
gn4124_dma_start
(
ft
);
status
=
gn4124_dma_wait_done
(
ft
,
10000
);
if
(
status
==
GENNUM_DMA_STA_ERROR
)
{
dev_err
(
ft
->
fmc
->
hwdev
,
"DMA transfer error
\n
"
);
ret
=
-
EIO
;
}
else
if
(
status
==
GENNUM_DMA_STA_ABORT
)
{
dev_err
(
ft
->
fmc
->
hwdev
,
"DMA transfer timeout or manually aborted
\n
"
);
ret
=
-
EIO
;
}
dma_unmap_sg
(
ft
->
fmc
->
hwdev
,
sgt
.
sgl
,
sgt
.
nents
,
dir
);
out_map_sg:
sg_free_table
(
&
sgt
);
out_sg_alloc:
dma_unmap_single
(
ft
->
fmc
->
hwdev
,
item_pool
,
sizeof
(
struct
gncore_dma_item
)
*
n
,
DMA_TO_DEVICE
);
out_dma_item:
kfree
(
item
);
return
ret
;
}
/**
* It performs a DMA test
* @ft FmcTDc instance
* @buf_size number of byte to transfer
* @use_sg 1 if you want to use scatterlists, 0 to do a single transfer
*
* It writes on the device memory a known pattern, then it reads it back
* and validate.
*
* The code will always prepare the SG table, but it will use it only
* when asked.
*
* Return: 0 on success, otherwise a negative error number
*/
int
test_dma
(
struct
fmctdc_dev
*
ft
,
unsigned
int
buf_size
,
unsigned
int
use_sg
)
{
const
int
buf_size
=
16
;
uint8_t
*
buf1
,
*
buf2
;
int
i
,
ret
=
0
;
uint32_t
eic
;
dev_dbg
(
&
ft
->
fmc
->
dev
,
"Test DMA
\n
"
);
/* Disable DMA interrupts, we do active waits here */
eic
=
ft_ioread
(
ft
,
ft
->
ft_dma_eic_base
+
DMA_EIC_REG_EIC_IMR
);
ft_iowrite
(
ft
,
eic
,
ft
->
ft_dma_eic_base
+
DMA_EIC_REG_EIC_IDR
);
buf1
=
kzalloc
(
PAGE_SIZE
,
GFP_KERNEL
);
/* Write buffer one */
buf1
=
kzalloc
(
buf_size
,
GFP_KERNEL
);
if
(
!
buf1
)
{
ret
=
-
ENOMEM
;
goto
out_buf1
;
}
buf2
=
kzalloc
(
PAGE_SIZE
,
GFP_KERNEL
);
if
(
!
buf2
)
{
ret
=
-
ENOMEM
;
for
(
i
=
0
;
i
<
buf_size
;
i
++
)
buf1
[
i
]
=
i
*
31011
+
12312
;
if
(
use_sg
)
ret
=
gn4124_dma_sg
(
ft
,
0
,
buf1
,
buf_size
,
DMA_TO_DEVICE
);
else
gn4124_dma_write
(
ft
,
0
,
buf1
,
buf_size
);
if
(
ret
<
0
)
goto
out_fail_w
;
/* Read buffer two */
buf2
=
kzalloc
(
buf_size
,
GFP_KERNEL
);
if
(
!
buf2
)
goto
out_buf2
;
}
dev_info
(
&
ft
->
fmc
->
dev
,
"Test DMA
\n
"
);
dev_info
(
&
ft
->
fmc
->
dev
,
"R0 = %08x R4 = %08x
\n
"
,
dma_readl
(
ft
,
0
),
dma_readl
(
ft
,
4
));
if
(
use_sg
)
ret
=
gn4124_dma_sg
(
ft
,
0
,
buf1
,
buf_size
,
DMA_FROM_DEVICE
);
else
gn4124_dma_read
(
ft
,
0
,
buf2
,
buf_size
);
/* mdelay(5000); */
if
(
ret
<
0
)
goto
out_fail_r
;
/* Validate */
for
(
i
=
0
;
i
<
buf_size
;
i
++
)
{
buf1
[
i
]
=
i
*
31011
+
12312
;
buf2
[
i
]
=
0xff
;
dev_vdbg
(
&
ft
->
fmc
->
dev
,
"%d 0x%02x 0x%02x
\n
"
,
i
,
buf1
[
i
],
buf2
[
i
]);
if
(
buf1
[
i
]
!=
buf2
[
i
])
{
dev_err
(
&
ft
->
fmc
->
dev
,
"ERROR %d 0x%02x 0x%02x
\n
"
,
i
,
buf1
[
i
],
buf2
[
i
]);
ret
=
-
EINVAL
;
}
}
gn4124_dma_write
(
ft
,
0
,
buf1
,
16
);
gn4124_dma_wait_done
(
ft
);
gn4124_dma_read
(
ft
,
0
,
buf2
,
16
);
gn4124_dma_wait_done
(
ft
);
for
(
i
=
0
;
i
<
buf_size
;
i
++
)
dev_info
(
&
ft
->
fmc
->
dev
,
"%02x %02x "
,
buf1
[
i
],
buf2
[
i
]);
dev_info
(
&
ft
->
fmc
->
dev
,
"
\n
"
);
out_fail_r:
kfree
(
buf2
);
out_buf2:
out_fail_w:
kfree
(
buf1
);
out_buf1:
/*
* clear any pending interrupt befre re-enabling, we have just
* generated and handled them here in this function
*/
ft_iowrite
(
ft
,
0xFFFFFFFF
,
ft
->
ft_dma_eic_base
+
DMA_EIC_REG_EIC_ISR
);
ft_iowrite
(
ft
,
eic
,
ft
->
ft_dma_eic_base
+
DMA_EIC_REG_EIC_IER
);
dev_dbg
(
&
ft
->
fmc
->
dev
,
"Test DMA complete %d
\n
"
,
ret
);
return
ret
;
}
#endif
/**
* It configures the test data
...
...
@@ -572,7 +707,6 @@ int ft_probe(struct fmc_device *fmc)
ft_writel
(
ft
,
TDC_CTRL_EN_ACQ
,
TDC_REG_CTRL
);
ft
->
initialized
=
1
;
test_dma
(
ft
);
/* Pin the carrier */
if
(
!
try_module_get
(
fmc
->
owner
))
...
...
kernel/ft-irq.c
View file @
b3f907e8
...
...
@@ -244,7 +244,7 @@ static void ft_readout_dma_run(struct zio_cset *cset,
dma_buf
=
cset
->
chan
->
active_block
->
data
;
gn4124_dma_read
(
ft
,
devmem
,
dma_buf
,
len
);
gn4124_dma_wait_done
(
ft
);
gn4124_dma_wait_done
(
ft
,
10000
);
}
/**
...
...
kernel/ft-zio.c
View file @
b3f907e8
...
...
@@ -39,6 +39,8 @@ static struct zio_attribute ft_zattr_dev[] = {
ZIO_ATTR_EXT
(
"command"
,
ZIO_WO_PERM
,
FT_ATTR_DEV_COMMAND
,
0
),
ZIO_ATTR_EXT
(
"wr-offset"
,
ZIO_RO_PERM
,
FT_ATTR_TDC_WR_OFFSET
,
0
),
ZIO_PARAM_EXT
(
"temperature"
,
ZIO_RO_PERM
,
FT_ATTR_PARAM_TEMP
,
0
),
ZIO_PARAM_EXT
(
"test_dma_sg"
,
ZIO_WO_PERM
,
FT_ATTR_PARAM_DMA_SG
,
0
),
ZIO_PARAM_EXT
(
"test_dma"
,
ZIO_WO_PERM
,
FT_ATTR_PARAM_DMA
,
0
),
};
/* Extended attributes for the TDC (== input) cset */
...
...
@@ -222,10 +224,12 @@ static int ft_zio_conf_set(struct device *dev, struct zio_attribute *zattr,
return
0
;
}
/* Not command, nothing to do */
if
(
zattr
->
id
!=
FT_ATTR_DEV_COMMAND
)
return
0
;
switch
(
zattr
->
id
)
{
case
FT_ATTR_PARAM_DMA_SG
:
return
test_dma
(
ft
,
usr_val
,
1
);
case
FT_ATTR_PARAM_DMA
:
return
test_dma
(
ft
,
usr_val
,
0
);
case
FT_ATTR_DEV_COMMAND
:
switch
(
usr_val
)
{
case
FT_CMD_SET_HOST_TIME
:
ft_set_host_time
(
ft
);
...
...
@@ -239,6 +243,7 @@ static int ft_zio_conf_set(struct device *dev, struct zio_attribute *zattr,
default:
return
-
EINVAL
;
}
}
}
...
...
kernel/hw/gennum-dma.h
View file @
b3f907e8
...
...
@@ -25,6 +25,15 @@ struct gncore_dma_item {
uint32_t
reserved
;
/* ouch */
};
#define GENUM_DMA_STA_MASK 0x7
enum
gncore_dma_status
{
GENNUM_DMA_STA_IDLE
=
0
,
GENNUM_DMA_STA_DONE
,
GENNUM_DMA_STA_BUSY
,
GENNUM_DMA_STA_ERROR
,
GENNUM_DMA_STA_ABORT
,
};
#define GENNUM_DMA_CTL 0x00
#define GENNUM_DMA_STA 0x04
#define GENNUM_DMA_ADDR 0x08
...
...
@@ -38,7 +47,6 @@ struct gncore_dma_item {
#define GENNUM_DMA_CTL_SWP 0xc
#define GENNUM_DMA_CTL_ABORT 0x2
#define GENNUM_DMA_CTL_START 0x1
#define GENNUM_DMA_STA_DONE 1 << 0
#define GENNUM_DMA_ATTR_DIR 0x00000002
#define GENNUM_DMA_ATTR_MORE 0x00000001
...
...
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