Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
W
wr-switch-sw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
white-rabbit
wr-switch-sw
Commits
995cf4db
Commit
995cf4db
authored
Dec 03, 2014
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel: add a clocksource module for WR time
Signed-off-by:
Alessandro Rubini
<
rubini@gnudd.com
>
parent
d1f405a9
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
199 additions
and
1 deletion
+199
-1
Makefile
kernel/Makefile
+1
-1
Makefile
kernel/wr_clocksource/Makefile
+25
-0
wr_clocksource.c
kernel/wr_clocksource/wr_clocksource.c
+173
-0
No files found.
kernel/Makefile
View file @
995cf4db
DIRS
=
wr_vic wr_nic wr_rtu at91_softpwm wr_pstats
DIRS
=
wr_vic wr_nic wr_rtu at91_softpwm wr_pstats
wr_clocksource
# We may "LINUX ?= /usr/src/linux-wrswitch", but it's better to leave it empty
...
...
kernel/wr_clocksource/Makefile
0 → 100644
View file @
995cf4db
obj-m
:=
wr_clocksource.o
# accept WRN_DEBUG from the environment. It turns pr_debug() into printk.
ifdef
WRN_DEBUG
ccflags-y
+=
-DDEBUG
endif
# What follows is standard stuff
export
ARCH
?=
arm
export
CROSS_COMPILE
?=
$(CROSS_COMPILE_ARM)
all modules
:
$(MAKE)
CONFIG_DEBUG_SECTION_MISMATCH
=
y
\
-C
$(LINUX)
SUBDIRS
=
$(
shell
/bin/pwd
)
modules
# looking at preprocessed output is helpful for bug hunting
preprocess
:
$(MAKE)
CONFIG_DEBUG_SECTION_MISMATCH
=
y
\
-C
$(LINUX)
SUBDIRS
=
$(
shell
/bin/pwd
)
$
(
wr-nic-objs:.o
=
.i
)
# We might "$(MAKE) -C $(LINUX)" but "make clean" with no LINUX defined
# is sometimes useful to have
clean
:
rm
-f
*
.mod.c
*
.o
*
.ko
*
.i .
*
cmd Module.symvers modules.order
*
~
rm
-rf
.tmp_versions
kernel/wr_clocksource/wr_clocksource.c
0 → 100644
View file @
995cf4db
/* Alessandro Rubini for CERN 2014, GPLv2 or later */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/vmalloc.h>
#include <linux/clocksource.h>
/* We need these two defined in order to include nic-hardware.h */
#define WR_IS_NODE 0
#define WR_IS_SWITCH 1
/* We have no centralized defines yet: pick frequency and registers base */
#include "../wr_nic/nic-hardware.h"
#define WRCS_FREQUENCY REFCLK_FREQ
#define WRCS_TICK_NS (NSEC_PER_SEC / WRCS_FREQUENCY)
static
int
wrcs_stats
;
module_param
(
wrcs_stats
,
int
,
0644
);
MODULE_PARM_DESC
(
wrcs_stats
,
"Count how often the clocksource is being read"
);
static
__iomem
struct
PPSG_WB
*
wrcs_ppsg
;
static
int
wrcs_is_registered
;
/* no need for atomic_t or whatever */
/* If so requested, print statistics once per second */
static
inline
void
wrcs_do_stats
(
void
)
{
static
unsigned
long
nextp
;
static
int
ncalls
;
if
(
!
wrcs_stats
)
return
;
if
(
!
nextp
)
nextp
=
jiffies
+
HZ
;
/* This, when enabled, shows around 400 calls per second */
if
(
time_after_eq
(
jiffies
,
nextp
))
{
pr_info
(
"%s: called %i times
\n
"
,
__func__
,
ncalls
);
ncalls
=
0
;
nextp
+=
HZ
;
}
ncalls
++
;
}
static
cycle_t
wrcs_read
(
struct
clocksource
*
cs
)
{
static
uint32_t
offset
,
last
,
this
;
wrcs_do_stats
();
/* FIXME: identify a time jump by monitoring the tick counter */
/*
* Turn the counter into a 32-bit one (see cs->mask below).
* We reset at 0x3b9aca0, so without this we should use mask = 0x1f
* and mac_idle = 32 ticks = 512ns. Unaffordable.
*/
this
=
readl
(
&
wrcs_ppsg
->
CNTR_NSEC
);
if
(
this
<
last
)
offset
+=
WRCS_FREQUENCY
;
last
=
this
;
return
offset
+
this
;
}
static
struct
clocksource
wrcs_cs
=
{
.
name
=
"white-rabbit"
,
.
rating
=
450
,
/* perfect... */
.
read
=
wrcs_read
,
/* no enable/disable */
.
mask
=
0xffffffff
,
/* We fake a 32-bit thing */
.
max_idle_ns
=
900
*
1000
*
1000
,
/* well, 1s... */
.
flags
=
CLOCK_SOURCE_IS_CONTINUOUS
,
};
/*
* The timer is used to check when does WR synchronize. When that
* happens, we set time of day and register our clocksource. Time
* jumps after synchronization are not well supported.
*/
static
void
wrcs_timer_fn
(
unsigned
long
unused
);
static
DEFINE_TIMER
(
wrcs_timer
,
wrcs_timer_fn
,
0
,
0
);
static
void
wrcs_timer_fn
(
unsigned
long
unused
)
{
uint32_t
ticks
,
tai_l
,
tai_h
;
int64_t
tai
;
/* Read ppsg, all fields consistently se we can use the value */
do
{
tai_l
=
readl
(
&
wrcs_ppsg
->
CNTR_UTCLO
);
tai_h
=
readl
(
&
wrcs_ppsg
->
CNTR_UTCHI
);
ticks
=
readl
(
&
wrcs_ppsg
->
CNTR_NSEC
);
}
while
(
readl
(
&
wrcs_ppsg
->
CNTR_UTCLO
)
!=
tai_l
);
tai
=
(
typeof
(
tai
))
tai_h
<<
32
|
tai_l
;
/* If we are before 2010 (date +%s --date=2010-01-01), try again */
if
(
tai
<
1262300400LL
)
{
mod_timer
(
&
wrcs_timer
,
jiffies
+
HZ
);
return
;
}
clocksource_register
(
&
wrcs_cs
);
wrcs_is_registered
=
1
;
/* And don't restart the timer */
}
static
int
wrcs_init
(
void
)
{
wrcs_ppsg
=
ioremap
(
FPGA_BASE_PPSG
,
FPGA_SIZE_PPSG
);
if
(
!
wrcs_ppsg
)
{
pr_err
(
"WR Clocksource: can't remap PPS registers
\n
"
);
return
-
EIO
;
}
clocksource_calc_mult_shift
(
&
wrcs_cs
,
WRCS_FREQUENCY
,
1
);
/* Fire the timer */
mod_timer
(
&
wrcs_timer
,
jiffies
+
HZ
);
return
0
;
}
static
void
wrcs_exit
(
void
)
{
del_timer_sync
(
&
wrcs_timer
);
if
(
wrcs_is_registered
)
clocksource_unregister
(
&
wrcs_cs
);
iounmap
(
wrcs_ppsg
);
}
module_init
(
wrcs_init
);
module_exit
(
wrcs_exit
);
MODULE_LICENSE
(
"GPL"
);
/* Hack: this is not exported by current kernel. Define a local copy */
void
clocks_calc_mult_shift
(
u32
*
mult
,
u32
*
shift
,
u32
from
,
u32
to
,
u32
maxsec
)
{
u64
tmp
;
u32
sft
,
sftacc
=
32
;
/*
* Calculate the shift factor which is limiting the conversion
* range:
*/
tmp
=
((
u64
)
maxsec
*
from
)
>>
32
;
while
(
tmp
)
{
tmp
>>=
1
;
sftacc
--
;
}
/*
* Find the conversion shift/mult pair which has the best
* accuracy and fits the maxsec conversion range:
*/
for
(
sft
=
32
;
sft
>
0
;
sft
--
)
{
tmp
=
(
u64
)
to
<<
sft
;
tmp
+=
from
/
2
;
do_div
(
tmp
,
from
);
if
((
tmp
>>
sftacc
)
==
0
)
break
;
}
*
mult
=
tmp
;
*
shift
=
sft
;
}
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