Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
Simple PCIe FMC carrier SPEC - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
3
Issues
3
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
Simple PCIe FMC carrier SPEC - Software
Commits
ab3f2f8d
Commit
ab3f2f8d
authored
Sep 25, 2012
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel/wr_nic: major cleanup of tx timestamping
Signed-off-by:
Alessandro Rubini
<
rubini@gnudd.com
>
parent
b242b877
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
43 additions
and
86 deletions
+43
-86
nic-core.c
kernel/wr_nic/nic-core.c
+2
-2
timestamp.c
kernel/wr_nic/timestamp.c
+35
-71
wr-nic.h
kernel/wr_nic/wr-nic.h
+6
-13
No files found.
kernel/wr_nic/nic-core.c
View file @
ab3f2f8d
...
...
@@ -193,7 +193,7 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The timestamp has not been collected: silently discard it */
}
wrn
->
skb_desc
[
desc
].
skb
=
skb
;
/* Save for tx irq and stamping */
wrn
->
skb_desc
[
desc
].
id
=
id
;
/* Save for tx irq and stamping */
wrn
->
skb_desc
[
desc
].
frame_
id
=
id
;
/* Save for tx irq and stamping */
//netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */
...
...
@@ -471,7 +471,7 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
/* hardware timestamping is enabled */
info
->
tx_flags
|=
SKBTX_IN_PROGRESS
;
pr_debug
(
"%s: %i -- in progress
\n
"
,
__func__
,
__LINE__
);
wrn_t
stamp_find
_skb
(
wrn
,
i
);
wrn_t
x_tstamp
_skb
(
wrn
,
i
);
/* It has been freed if found; otherwise keep it */
}
else
{
dev_kfree_skb_irq
(
skb
);
...
...
kernel/wr_nic/timestamp.c
View file @
ab3f2f8d
...
...
@@ -15,40 +15,29 @@
#include "wr-nic.h"
/* This
looks for an skb in the already-received stamp lis
t */
void
wrn_t
stamp_find
_skb
(
struct
wrn_dev
*
wrn
,
int
desc
)
/* This
checks if we already received the timestamp interrup
t */
void
wrn_t
x_tstamp
_skb
(
struct
wrn_dev
*
wrn
,
int
desc
)
{
struct
skb_shared_hwtstamps
*
hwts
;
struct
sk_buff
*
skb
=
wrn
->
skb_desc
[
desc
].
skb
;
struct
wrn_desc_pending
*
d
=
wrn
->
skb_desc
+
desc
;
struct
sk_buff
*
skb
=
d
->
skb
;
struct
timespec
ts
;
int
id
=
wrn
->
skb_desc
[
desc
].
id
;
u32
counter_ppsg
;
/* PPS generator nanosecond counter */
u32
utc
;
int
i
;
/* FIXME: use list for faster access */
for
(
i
=
0
;
i
<
WRN_TS_BUF_SIZE
;
i
++
)
if
(
wrn
->
ts_buf
[
i
].
valid
&&
wrn
->
ts_buf
[
i
].
frame_id
==
id
)
break
;
if
(
i
==
WRN_TS_BUF_SIZE
)
{
pr_debug
(
"%s: not found
\n
"
,
__func__
);
if
(
!
wrn
->
skb_desc
[
desc
].
valid
)
return
;
}
pr_debug
(
"%s: found
\n
"
,
__func__
);
/*
so we found the skb,
do the timestamping magic */
/*
already reported by hardware:
do the timestamping magic */
wrn_ppsg_read_time
(
wrn
,
&
counter_ppsg
,
&
utc
);
/* The timestamp nanoseconds value is closer to the end of previous second, but the UTC time
read from PPSG is at the beginning of the next second: adjust UTC seconds to avoid 1 sec
"jump" */
if
(
counter_ppsg
<
REFCLK_FREQ
/
4
&&
wrn
->
ts_buf
[
i
].
ts
>
3
*
REFCLK_FREQ
/
4
)
/* We may be at the beginning og the next second */
if
(
counter_ppsg
<
d
->
cycles
)
utc
--
;
ts
.
tv_sec
=
(
s32
)
utc
&
0x7fffffff
;
ts
.
tv_nsec
=
wrn
->
ts_buf
[
i
].
ts
*
NSEC_PER_TICK
;
if
(
!
(
wrn
->
ts_buf
[
i
].
valid
&
TS_INVALID
))
{
ts
.
tv_nsec
=
d
->
cycles
*
NSEC_PER_TICK
;
if
(
!
(
d
->
valid
&
TS_INVALID
))
{
hwts
=
skb_hwtstamps
(
skb
);
hwts
->
hwtstamp
=
timespec_to_ktime
(
ts
);
skb_tstamp_tx
(
skb
,
hwts
);
...
...
@@ -56,70 +45,50 @@ void wrn_tstamp_find_skb(struct wrn_dev *wrn, int desc)
dev_kfree_skb_irq
(
skb
);
/* release both the descriptor and the tstamp entry */
wrn
->
skb_desc
[
desc
].
skb
=
0
;
wrn
->
ts_buf
[
i
].
valid
=
0
;
d
->
skb
=
0
;
d
->
valid
=
0
;
}
/* This function
records the timestamp in a list -- called from interrupt
*/
/* This function
, called by txtsu records the timestamp for the descriptor
*/
static
int
record_tstamp
(
struct
wrn_dev
*
wrn
,
u32
tsval
,
u32
idreg
,
u32
r2
)
{
int
port_id
=
TXTSU_TSF_R1_PID_R
(
idreg
);
int
frame_id
=
TXTSU_TSF_R1_FID_R
(
idreg
);
int
ts_incorrect
=
r2
&
TXTSU_TSF_R2_INCORRECT
;
struct
skb_shared_hwtstamps
*
hwts
;
struct
timespec
ts
;
struct
sk_buff
*
skb
;
u32
utc
,
counter_ppsg
;
/* PPS generator nanosecond counter */
int
i
;
/* FIXME: use list for faster access */
int
i
;
if
(
0
)
printk
(
"%s: Got TS: %x pid %d fid %d
\n
"
,
__func__
,
tsval
,
port_id
,
frame_id
);
/* First of all look if the skb is already pending */
/* Find the skb in the descriptor array */
for
(
i
=
0
;
i
<
WRN_NR_DESC
;
i
++
)
if
(
wrn
->
skb_desc
[
i
].
skb
&&
wrn
->
skb_desc
[
i
].
id
==
frame_id
)
if
(
wrn
->
skb_desc
[
i
].
skb
&&
wrn
->
skb_desc
[
i
].
frame_id
==
frame_id
)
break
;
if
(
i
<
WRN_NR_DESC
)
{
/*printk("%s: found\n", __func__);*/
skb
=
wrn
->
skb_desc
[
i
].
skb
;
if
(
i
==
WRN_NR_DESC
)
{
/* Not found: Must be a PTP frame sent from the SPEC! */
return
0
;
}
wrn_ppsg_read_time
(
wrn
,
&
counter_ppsg
,
&
utc
)
;
skb
=
wrn
->
skb_desc
[
i
].
skb
;
if
(
counter_ppsg
<
(
tsval
&
0xfffffff
))
utc
--
;
wrn_ppsg_read_time
(
wrn
,
&
counter_ppsg
,
&
utc
);
ts
.
tv_sec
=
(
s32
)
utc
&
0x7fffffff
;
ts
.
tv_nsec
=
(
tsval
&
0xfffffff
)
*
NSEC_PER_TICK
;
if
(
counter_ppsg
<
(
tsval
&
0xfffffff
))
utc
--
;
/* Provide the timestamp for the userland only if we're 100% sure about its correctness */
if
(
!
ts_incorrect
)
{
hwts
=
skb_hwtstamps
(
skb
);
hwts
->
hwtstamp
=
timespec_to_ktime
(
ts
);
skb_tstamp_tx
(
skb
,
hwts
);
}
dev_kfree_skb_irq
(
skb
);
wrn
->
skb_desc
[
i
].
skb
=
0
;
return
0
;
}
/* Otherwise, save it to the list, in an empty slot */
for
(
i
=
0
;
i
<
WRN_TS_BUF_SIZE
;
i
++
)
if
(
!
wrn
->
ts_buf
[
i
].
valid
)
break
;
ts
.
tv_sec
=
(
s32
)
utc
&
0x7fffffff
;
ts
.
tv_nsec
=
(
tsval
&
0xfffffff
)
*
NSEC_PER_TICK
;
if
(
i
==
WRN_TS_BUF_SIZE
)
{
pr_debug
(
"%s: ENOMEM
\n
"
,
__func__
);
return
-
ENOMEM
;
/* Provide the timestamp only if 100% sure about its correctness */
if
(
!
ts_incorrect
)
{
hwts
=
skb_hwtstamps
(
skb
);
hwts
->
hwtstamp
=
timespec_to_ktime
(
ts
);
skb_tstamp_tx
(
skb
,
hwts
);
}
pr_debug
(
"%s: save to slot %i
\n
"
,
__func__
,
i
);
wrn
->
ts_buf
[
i
].
ts
=
tsval
;
wrn
->
ts_buf
[
i
].
port_id
=
port_id
;
wrn
->
ts_buf
[
i
].
frame_id
=
frame_id
;
wrn
->
ts_buf
[
i
].
valid
=
TS_PRESENT
;
if
(
ts_incorrect
)
wrn
->
ts_buf
[
i
].
valid
|=
TS_INVALID
;
dev_kfree_skb_irq
(
skb
);
wrn
->
skb_desc
[
i
].
skb
=
0
;
return
0
;
}
...
...
@@ -135,11 +104,7 @@ irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id)
r1
=
readl
(
&
regs
->
TSF_R1
);
r2
=
readl
(
&
regs
->
TSF_R2
);
if
(
record_tstamp
(
wrn
,
r0
,
r1
,
r2
)
<
0
)
{
printk
(
"%s: ENOMEM in the TS buffer. Disabling TX stamping.
\n
"
,
__func__
);
writel
(
TXTSU_EIC_IER_NEMPTY
,
&
wrn
->
txtsu_regs
->
EIC_IDR
);
}
record_tstamp
(
wrn
,
r0
,
r1
,
r2
);
writel
(
TXTSU_EIC_IER_NEMPTY
,
&
wrn
->
txtsu_regs
->
EIC_ISR
);
/* ack irq */
return
IRQ_HANDLED
;
}
...
...
@@ -196,7 +161,6 @@ int wrn_tstamp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
void
wrn_tstamp_init
(
struct
wrn_dev
*
wrn
)
{
memset
(
wrn
->
ts_buf
,
0
,
sizeof
(
wrn
->
ts_buf
));
/* enable TXTSU irq */
writel
(
TXTSU_EIC_IER_NEMPTY
,
&
wrn
->
txtsu_regs
->
EIC_IER
);
}
...
...
kernel/wr_nic/wr-nic.h
View file @
ab3f2f8d
...
...
@@ -55,27 +55,21 @@
#define WRN_IRQ_NAMES {"wr-nic", "wr-tstamp"}
#define WRN_IRQ_HANDLERS {wrn_interrupt, wrn_tstamp_interrupt}
#define WRN_TS_BUF_SIZE 1024
/* array of timestamp structures */
struct
wrn_ep
;
/* Defined later */
/* A timestamping structure to keep information for user-space */
struct
wrn_tx_tstamp
{
/* We must remember skb, id and tstamp for each pending descriptor, */
struct
wrn_desc_pending
{
struct
sk_buff
*
skb
;
u8
valid
;
u8
port_id
;
u16
frame_id
;
u32
t
s
;
u32
cycle
s
;
};
/* bits for "valid" field */
#define TS_PRESENT 1
#define TS_INVALID 2
/* as reported by hw: we return 0 as timestamp */
/* We must remember both skb and id for each pending descriptor */
struct
wrn_desc_pending
{
struct
sk_buff
*
skb
;
u32
id
;
/* only 16 bits, actually */
};
/*
* This is the main data structure for our NIC device. As for locking,
* the rule is that _either_ the wrn _or_ the endpoint is locked. Not both.
...
...
@@ -101,7 +95,6 @@ struct wrn_dev {
int
id
;
struct
net_device
*
dev
[
WRN_NR_ENDPOINTS
];
struct
wrn_tx_tstamp
ts_buf
[
WRN_TS_BUF_SIZE
];
/* FIXME: all dev fields must be verified */
...
...
@@ -237,7 +230,7 @@ extern int wrn_endpoint_probe(struct net_device *netdev);
extern
void
wrn_endpoint_remove
(
struct
net_device
*
netdev
);
/* Following functions from timestamp.c */
extern
void
wrn_t
stamp_find_skb
(
struct
wrn_dev
*
wrn
,
int
i
);
extern
void
wrn_t
x_tstamp_skb
(
struct
wrn_dev
*
wrn
,
int
desc
);
extern
int
wrn_tstamp_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
extern
irqreturn_t
wrn_tstamp_interrupt
(
int
irq
,
void
*
dev_id
);
extern
void
wrn_tstamp_init
(
struct
wrn_dev
*
wrn
);
...
...
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