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
2d80667f
Commit
2d80667f
authored
Sep 26, 2018
by
Tomasz Wlostowski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel: fix race condition in DMA irq
parent
4dbf3185
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
23 additions
and
0 deletions
+23
-0
fmc-tdc.h
kernel/fmc-tdc.h
+2
-0
ft-irq.c
kernel/ft-irq.c
+21
-0
No files found.
kernel/fmc-tdc.h
View file @
2d80667f
...
...
@@ -208,6 +208,8 @@ struct fmctdc_dev {
struct
zio_dma_sgt
*
zdma
;
int
dma_chan_mask
;
/* interrupt lock to prevent triggering a DMA access while the previous one is still running */
spinlock_t
dma_lock
;
};
static
inline
u32
ft_ioread
(
struct
fmctdc_dev
*
ft
,
unsigned
long
addr
)
...
...
kernel/ft-irq.c
View file @
2d80667f
...
...
@@ -284,6 +284,19 @@ static void ft_dma_work(struct work_struct *work)
int
i
,
err
,
transfer
,
n_block
;
unsigned
long
*
loop
;
/* The code below prevents a race condition between the ft_dma_work interrupt and
the DMA complete handler. On some systems (in particular multicore) and some patterns
of input timestamps, an IRQ for one of the TDC channels can be triggered while the DMA
transfer is still in progress. In the worst case, the call of zio_dma_alloc_sg few lines below
this comment will overwrite a pointer being used (in parallel CPU core) by ft_irq_handler_dma_complete().
Sometimes this would drop a kernel crash or produce incorrect timestamps.
Since DMA xfers in GN4124 cannot be queued, we prevent this by
a simple, crude spinlock (David, Fede, fixme please ;-) */
if
(
!
spin_trylock
(
&
ft
->
dma_lock
))
return
;
irq_stat
=
ft_ioread
(
ft
,
ft
->
ft_irq_base
+
TDC_EIC_REG_EIC_ISR
);
irq_stat
&=
TDC_EIC_EIC_IMR_TDC_DMA_MASK
;
...
...
@@ -343,6 +356,7 @@ err_alloc:
zio_trigger_abort_disable
(
&
ft
->
zdev
->
cset
[
i
],
0
);
}
spin_unlock
(
&
ft
->
dma_lock
);
ft_irq_enable_restore
(
ft
);
}
...
...
@@ -453,7 +467,10 @@ static irqreturn_t ft_irq_handler_dma_complete(int irq, void *dev_id)
irq_stat
=
ft_ioread
(
ft
,
ft
->
ft_dma_eic_base
+
DMA_EIC_REG_EIC_ISR
);
if
(
!
irq_stat
)
{
spin_unlock
(
&
ft
->
dma_lock
);
return
IRQ_NONE
;
}
ft_iowrite
(
ft
,
irq_stat
,
ft
->
ft_dma_eic_base
+
TDC_EIC_REG_EIC_ISR
);
loop
=
(
unsigned
long
*
)
&
ft
->
dma_chan_mask
;
...
...
@@ -486,6 +503,8 @@ static irqreturn_t ft_irq_handler_dma_complete(int irq, void *dev_id)
out:
fmc_irq_ack
(
fmc
);
spin_unlock
(
&
ft
->
dma_lock
);
/* Re-Enable interrupts that were disabled in the IRQ handler */
ft_irq_enable_restore
(
ft
);
...
...
@@ -644,6 +663,8 @@ int ft_irq_init(struct fmctdc_dev *ft)
{
int
ret
;
spin_lock_init
(
&
ft
->
dma_lock
);
ft_irq_coalescing_timeout_set
(
ft
,
-
1
,
irq_timeout_ms_default
);
ft_irq_coalescing_size_set
(
ft
,
-
1
,
40
);
...
...
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