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
ce1cae21
Commit
ce1cae21
authored
Sep 20, 2012
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel,user,doc: added mode-setting for the channels
Signed-off-by:
Alessandro Rubini
<
rubini@gnudd.com
>
parent
f7422fd0
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
209 additions
and
11 deletions
+209
-11
spec-sw.in
doc/spec-sw.in
+42
-1
wr-dio.h
kernel/wr-dio.h
+6
-1
wr-nic-dio.c
kernel/wr-nic-dio.c
+64
-4
wr-dio-cmd.c
tools/wr-dio-cmd.c
+97
-5
No files found.
doc/spec-sw.in
View file @
ce1cae21
...
...
@@ -621,7 +621,12 @@ generated a MAC address using the serial number of the internal
thermometer.
The user is thus only expected to assign an Internet address to the
Ethernet port and just use it to transfer data.
Ethernet port and just use it to transfer data. If you need to change
the MAC address, the command you need is something like the following:
@example
ifconfig wr0 hw ether 12:34:56:78:9a:bc
@end example
The port supports hardware timestamping for user frames through the
standard Linux mechanisms, but at this point no sample code is provided
...
...
@@ -779,8 +784,44 @@ The current version of the tool supports the following commands:
is not modified. The @code
{
+
}
form is useful for simple checks with
visual inspection.
@item mode <channel> <mode> [<channel> <mode> ...]
@itemx mode <mode0><mode1><mode2><mode3><mode4>
Configure one or more channel for the specified mode. Each mode
is one character, so the second form receives a 5-byte
string argument. Available modes are ``@code
{
I
}
'' (input),
``@code
{
0
}
'' and ``@code
{
1
}
'' (output, steady state),
``@code
{
D
}
'' (DIO core output) or ``@code
{
-
}
'' (unchanged).
A channel managed by the DIO core is normally low and can
pulse high on request (see @code
{
pulse
}
command. Uppercase @code
{
D
}
or @code
{
I
}
select the termination
resistor, while lowercase @code
{
d
}
or @code
{
i
}
disable the termination
(output is always without termination, but I may add @code
{
L
}
and
@code
{
H
}
if needed: the driver supports all combinations).
Please note that the @code
{
pulse
}
command turns the affected channel in
@i
{
DIO
}
mode anyways (without changing the termination).
@end table
Example uses of the tool follow:
@example
# Pulse channel 4 for 0.1 seconds now
wr-dio-cmd wr0 pulse 4 .1 now
# Pulse for 10 microseconds in the middle of the next second
wr-dio-cmd wr0 pulse 4 .00001 +1.5
# Pulse for 1ms at 17:00 today
wr-dio-cmd wr0 pulse 4 .001
$
(
date
+
%s --date 17:00)
# Get timestamps for the output events above
wr
-
dio
-
cmd wr
0
stamp
4
# Configure channel
0
as input with termination,
1
as input,
4
as low
wr
-
dio
-
cmd wr
0
mode Ii
--
0
@end example
@c
==========================================================================
@node The Future of WR
-
NIC
@section The Future of WR
-
NIC
...
...
kernel/wr-dio.h
View file @
ce1cae21
...
...
@@ -56,9 +56,14 @@ enum wr_dio_cmd_name {
* CMD_INOUT:
* cmd->flags: F_MASK
* cmd->channel: the channel or the mask
* cmd->value: bits 0..4:
data, bits 8..12 OEN (high active), 16..20
term
* cmd->value: bits 0..4:
WR-DIO, 8..12 value, 16..20 OEN, 24..28
term
*/
#define WR_DIO_INOUT_DIO (1 << 0)
#define WR_DIO_INOUT_VALUE (1 << 8)
#define WR_DIO_INOUT_OUTPUT (1 << 16)
#define WR_DIO_INOUT_TERM (1 << 24)
#define WR_DIO_N_STAMP 16
/* At least 5 * 3 */
struct
wr_dio_cmd
{
...
...
kernel/wr-nic-dio.c
View file @
ce1cae21
...
...
@@ -102,15 +102,15 @@ static int wrn_dio_cmd_pulse(struct wrn_drvdata *drvdata,
struct
PPSG_WB
__iomem
*
ppsg
=
drvdata
->
ppsg_base
;
struct
regmap
*
map
;
struct
timespec
*
ts
;
uint32_t
val
;
uint32_t
reg
;
if
(
cmd
->
channel
>
4
)
return
-
EINVAL
;
/* FIXME: mask */
map
=
regmap
+
cmd
->
channel
;
/* First, put this bit as output (FIXME: plain GPIO support?) */
val
=
readl
(
&
dio
->
OUT
)
|
(
1
<<
cmd
->
channel
);
writel
(
val
,
&
dio
->
OUT
);
reg
=
readl
(
&
dio
->
OUT
)
|
(
1
<<
cmd
->
channel
);
writel
(
reg
,
&
dio
->
OUT
);
ts
=
cmd
->
t
;
...
...
@@ -208,6 +208,64 @@ static int wrn_dio_cmd_stamp(struct wrn_drvdata *drvdata,
return
0
;
}
static
int
wrn_dio_cmd_inout
(
struct
wrn_drvdata
*
drvdata
,
struct
wr_dio_cmd
*
cmd
)
{
struct
DIO_WB
__iomem
*
dio
=
drvdata
->
wrdio_base
;
int
mask
,
ch
,
last
,
bits
;
uint32_t
reg
;
if
(
cmd
->
flags
&
WR_DIO_F_MASK
)
{
ch
=
0
;
last
=
4
;
mask
=
cmd
->
channel
;
}
else
{
ch
=
cmd
->
channel
;
last
=
ch
;
mask
=
(
1
<<
ch
);
cmd
->
value
<<=
ch
;
}
/* handle the 1-channel and mask case in the same loop */
for
(;
ch
<=
last
;
ch
++
)
{
if
(((
1
<<
ch
)
&
mask
)
==
0
)
continue
;
/* select the bits by shifting back the value field */
bits
=
cmd
->
value
>>
ch
;
/* termination is bit 2 (0x4); register 0 clears, reg 4 sets */
if
(
bits
&
WR_DIO_INOUT_TERM
)
writel
(
0x4
<<
(
4
*
ch
),
drvdata
->
gpio_base
+
4
);
else
writel
(
0x4
<<
(
4
*
ch
),
drvdata
->
gpio_base
+
0
);
reg
=
readl
(
&
dio
->
OUT
)
&
~
(
1
<<
ch
);
if
(
bits
&
WR_DIO_INOUT_DIO
)
{
writel
(
reg
|
(
1
<<
ch
),
&
dio
->
OUT
);
continue
;
/* if DIO, nothing more to do */
}
/* If not DIO, wait after we know if input or output */
if
(
!
(
bits
&
WR_DIO_INOUT_OUTPUT
))
{
/* output-enable is low-active, so set bit 1 (0x2) */
writel
(
0x2
<<
(
4
*
ch
),
drvdata
->
gpio_base
+
4
);
writel
(
reg
,
&
dio
->
OUT
);
/* not DIO */
continue
;
/* input, no value to be set */
}
/* Output value is bit 0 (0x1) */
if
(
bits
&
WR_DIO_INOUT_VALUE
)
writel
(
0x1
<<
(
4
*
ch
),
drvdata
->
gpio_base
+
4
);
else
writel
(
0x1
<<
(
4
*
ch
),
drvdata
->
gpio_base
+
0
);
/* Then clear the low-active output enable, bit 1 (0x2) */
writel
(
0x2
<<
(
4
*
ch
),
drvdata
->
gpio_base
+
0
);
writel
(
reg
,
&
dio
->
OUT
);
/* not DIO */
}
return
0
;
}
int
wrn_mezzanine_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
ioctlcmd
)
...
...
@@ -241,8 +299,10 @@ int wrn_mezzanine_ioctl(struct net_device *dev, struct ifreq *rq,
case
WR_DIO_CMD_STAMP
:
ret
=
wrn_dio_cmd_stamp
(
drvdata
,
cmd
);
break
;
case
WR_DIO_CMD_DAC
:
case
WR_DIO_CMD_INOUT
:
ret
=
wrn_dio_cmd_inout
(
drvdata
,
cmd
);
break
;
case
WR_DIO_CMD_DAC
:
ret
=
-
ENOTSUPP
;
goto
out
;
default:
...
...
tools/wr-dio-cmd.c
View file @
ce1cae21
...
...
@@ -136,7 +136,7 @@ static int scan_stamp(int argc, char **argv, int ismask)
break
;
fprintf
(
stderr
,
"%s: ioctl(PRIV_MEZZANINE_CMD(%s)): "
"%s
\n
"
,
prgname
,
ifname
,
strerror
(
errno
));
return
-
1
;
return
-
1
;
}
for
(
i
=
0
;
i
<
cmd
->
nstamp
;
i
++
)
printf
(
"ch %i, %9li.%09li
\n
"
,
cmd
->
channel
,
...
...
@@ -145,6 +145,92 @@ static int scan_stamp(int argc, char **argv, int ismask)
return
0
;
}
static
int
one_mode
(
int
c
,
int
index
)
{
if
(
c
==
'-'
)
return
0
;
cmd
->
channel
|=
1
<<
index
;
switch
(
c
)
{
case
'D'
:
cmd
->
value
|=
WR_DIO_INOUT_DIO
<<
index
;
cmd
->
value
|=
WR_DIO_INOUT_TERM
<<
index
;
break
;
case
'd'
:
cmd
->
value
|=
WR_DIO_INOUT_DIO
<<
index
;
break
;
case
'I'
:
cmd
->
value
|=
WR_DIO_INOUT_TERM
<<
index
;
case
'i'
:
break
;
case
'1'
:
cmd
->
value
|=
WR_DIO_INOUT_VALUE
<<
index
;
case
'0'
:
cmd
->
value
|=
WR_DIO_INOUT_OUTPUT
<<
index
;
break
;
default:
fprintf
(
stderr
,
"%s: mode: invalid mode '%c'
\n
"
,
prgname
,
c
);
return
-
1
;
}
return
0
;
}
static
int
scan_inout
(
int
argc
,
char
**
argv
)
{
int
i
,
ch
;
char
c
;
cmd
->
flags
=
WR_DIO_F_MASK
;
cmd
->
channel
=
0
;
cmd
->
value
=
0
;
if
(
argc
==
2
)
{
if
(
strlen
(
argv
[
1
])
!=
5
)
{
fprintf
(
stderr
,
"%s: %s: wrong argument
\"
%s
\"\n
"
,
prgname
,
argv
[
0
],
argv
[
1
]);
exit
(
1
);
}
for
(
i
=
0
;
i
<
5
;
i
++
)
if
(
one_mode
(
argv
[
1
][
i
],
i
)
<
0
)
return
-
1
;
}
else
{
if
(
argc
<
3
||
argc
>
11
||
((
argc
&
1
)
==
0
))
{
fprintf
(
stderr
,
"%s: %s: wrong number of arguments
\n
"
,
prgname
,
argv
[
0
]);
return
-
1
;
}
while
(
argc
>=
3
)
{
if
(
sscanf
(
argv
[
1
],
"%i%c"
,
&
ch
,
&
c
)
!=
1
||
ch
<
0
||
ch
>
4
)
{
fprintf
(
stderr
,
"%s: mode: invalid channel "
"
\"
%s
\"\n
"
,
prgname
,
argv
[
1
]);
return
-
1
;
}
if
(
strlen
(
argv
[
2
])
!=
1
)
{
fprintf
(
stderr
,
"%s: mode: invalid mode "
"
\"
%s
\"\n
"
,
prgname
,
argv
[
2
]);
return
-
1
;
}
if
(
one_mode
(
argv
[
2
][
0
],
ch
)
<
0
)
return
-
1
;
argv
+=
2
;
argc
-=
2
;
}
}
ifr
.
ifr_data
=
(
void
*
)
cmd
;
if
(
ioctl
(
sock
,
PRIV_MEZZANINE_CMD
,
&
ifr
)
<
0
)
{
fprintf
(
stderr
,
"%s: ioctl(PRIV_MEZZANINE_CMD(%s)): %s
\n
"
,
prgname
,
ifname
,
strerror
(
errno
));
return
-
1
;
}
return
0
;
}
int
main
(
int
argc
,
char
**
argv
)
{
...
...
@@ -182,12 +268,14 @@ int main(int argc, char **argv)
* pulse <ch> .<len> now
* pulse <ch> .<len> +<seconds>.<fraction>
*
* TODO: stamp <channel>
* TODO: stampm <mask>
**/
* stamp [<channel>]
* stampm [<mask>]
*
* mode <01234>
* mode <ch> <mode> [...]
*/
if
(
!
strcmp
(
argv
[
0
],
"pulse"
))
{
cmd
->
command
=
WR_DIO_CMD_PULSE
;
if
(
scan_pulse
(
argc
,
argv
)
<
0
)
exit
(
1
);
}
else
if
(
!
strcmp
(
argv
[
0
],
"stamp"
))
{
...
...
@@ -198,6 +286,10 @@ int main(int argc, char **argv)
cmd
->
command
=
WR_DIO_CMD_STAMP
;
if
(
scan_stamp
(
argc
,
argv
,
1
/* mask */
)
<
0
)
exit
(
1
);
}
else
if
(
!
strcmp
(
argv
[
0
],
"mode"
))
{
cmd
->
command
=
WR_DIO_CMD_INOUT
;
if
(
scan_inout
(
argc
,
argv
)
<
0
)
exit
(
1
);
}
else
{
fprintf
(
stderr
,
"%s: unknown command
\"
%s
\"\n
"
,
prgname
,
argv
[
0
]);
...
...
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