Skip to content
Snippets Groups Projects
spec-sw.in 54.8 KiB
Newer Older
Alessandro Rubini's avatar
Alessandro Rubini committed
\input texinfo    @c -*-texinfo-*-
%
% spec-sw.in - main file for the documentation
%
%%%%

%------------------------------------------------------------------------------
%
%                         NOTE FOR THE UNAWARE USER
%                         =========================
%
%    This file is a texinfo source. It isn't the binary file of some strange
%    editor of mine. If you want ASCII, you should "make spec-sw.txt".
%
%------------------------------------------------------------------------------

%
% This is not a conventional info file...
% I use three extra features:
%   - The '%' as a comment marker, if at beginning of line ("\%" -> "%")
%   - leading blanks are allowed (this is something I can't live without)
%   - braces are automatically escaped when they appear in example blocks
%

@comment %**start of header
@documentlanguage en
@setfilename spec-sw.info
@settitle spec-sw
@iftex
@afourpaper
@end iftex
@comment %**end of header

@setchapternewpage off

Alessandro Rubini's avatar
Alessandro Rubini committed
@set update-month October 2012
Alessandro Rubini's avatar
Alessandro Rubini committed

@finalout

@titlepage
Alessandro Rubini's avatar
Alessandro Rubini committed
@title SPEC Software Support
@subtitle (@value{update-month})
Alessandro Rubini's avatar
Alessandro Rubini committed
@subtitle A driver for the SPEC card and its FMC modules
@author Alessandro Rubini for CERN (BE-CO-HT)
Alessandro Rubini's avatar
Alessandro Rubini committed
@end titlepage
@headings single

@c ##########################################################################
@iftex
@contents
@end iftex

Alessandro Rubini's avatar
Alessandro Rubini committed
@c ##########################################################################
@node Top
@top Introduction

Alessandro Rubini's avatar
Alessandro Rubini committed
This is the manual for the SPEC device driver. SPEC is the @i{Simple
PCI-Express Carrier} for FMC cards, developed at
@url{http://www.ohwr.org/projects/spec}. This manual is part of the
associated software project, hosted at
@url{http://www.ohwr.org/projects/spec-sw}. The latest version of
this work is always available in the @i{git} repository at @code{ohwr.org}.
Alessandro Rubini's avatar
Alessandro Rubini committed

Alessandro Rubini's avatar
Alessandro Rubini committed
@c ##########################################################################
@node History and Overview
@chapter History and Overview
Alessandro Rubini's avatar
Alessandro Rubini committed

This driver is pretty different from the initial implementation, such as
the one used by @i{fine-delay-sw-v1.1}.  If you are using that version, please
compile the manual you find in your source code repository and avoid
reading this one.
Alessandro Rubini's avatar
Alessandro Rubini committed

The package currently includes both the @i{spec} driver and the
@i{fmc} bus driver (documented separately).
Moreover, it includes some drivers for fmc cards.
Alessandro Rubini's avatar
Alessandro Rubini committed

@c ##########################################################################
@node Compiling the Drivers
@chapter Compiling the Drivers
Alessandro Rubini's avatar
Alessandro Rubini committed

The kernel modules that are part of this package live in the @i{kernel}
subdirectory. To compile them, you need to 
set the following variables in your environment:
Alessandro Rubini's avatar
Alessandro Rubini committed

@table @code

@item LINUX

	The top directory of the kernel sources for the version you
        are going to run the driver under. I'm testing mostly with 3.4,
	but this version compiles against Linux-2.6.37 and later ones
        (2.6.36 had a different interface for hardware timestamping,
        so @i{fmc} and @i{spec} compile fine, but @i{wr-nic} does not).
Alessandro Rubini's avatar
Alessandro Rubini committed

@item CROSS_COMPILE

	If you are cross-compiling, you need to set this variable.
	It is not usually needed for the PC, but if you are using
        the @i{Powec} board, you'll most likely need this. It is not
        needed if you compile for a different-sized PC (see below).

@item ARCH

	If you are cross-compiling, set this variable. Use @code{powerpc}
        for the @i{Powec}, @code{x86-64} if you compile on a 32-bit PC
        to run on a 64-bit PC and @code{i386} if you compile on a 64-bit
        PC to run on a 32-bit PC.

@end table

To compile run ``@code{make}'' with the previous variables set.  To
install run ``@code{make install} to install under
@code{/lib/modules/3.4.0} (or other version-based directory).  You can
set @code{INSTALL_MOD_PATH} to force and installation directory
(as a prefix followed by @code{/lib/modules/...}).
Alessandro Rubini's avatar
Alessandro Rubini committed
For example, if your target computer's filesystem is mounted under
@code{/mnt/target} you can run

@example
   make install INSTALL_MOD_PATH=/mnt/target
@end example

The modules are installed under the subdirectory @code{extra}. In
the case shown above your driver will end up being installed
(together with the other modules) as
Alessandro Rubini's avatar
Alessandro Rubini committed

@example
   /mnt/target/lib/modules/3.4.0/extra/spec.ko
Alessandro Rubini's avatar
Alessandro Rubini committed
@end example

@c ##########################################################################
@node Role of spec.ko
@chapter Role of spec.ko
Alessandro Rubini's avatar
Alessandro Rubini committed

The @code{spec.ko} driver depends on @code{fmc.ko}, that must
be loaded first (if you don't rely on automatic dependencies).

@code{spec.ko} registers as a PCI driver,
using both the ``old'' identifiers (i.e. the Gennum vendor and GN4124 device)
Alessandro Rubini's avatar
Alessandro Rubini committed
and the new ones (CERN vendor and SPEC device).

@c ==========================================================================
@node SPEC Initialization
@section SPEC Initialization

For each new SPEC device found on the system, the driver performs the
following steps:
Alessandro Rubini's avatar
Alessandro Rubini committed

@itemize @bullet
@item It enables MSI interrupts, the only ones supported in this package.
@item It loads the @code{fmc/spec-init.bin} ``golden'' gateware file.
@item It checks that the content of the binary is as expected (using
      a minimal @i{sdb}-based verification).
@item It reads the whole I2C EEPROM found on the mezzanine.
@item It allocates an @i{fmc_device} structure and registers as
Erik van der Bij's avatar
Erik van der Bij committed
      a new device in the @i{fmc} bus.
Alessandro Rubini's avatar
Alessandro Rubini committed
@end itemize

Failure of any of the above steps is fatal.

The suggested @code{spec-init.bin} gateware binary is always available
from the @i{files} area of the @i{spec-sw} project on @code{ohwr.org}.
The current binary version to be used with this software version is
@url{http://www.ohwr.org/attachments/download/1454/spec-init.bin-2012-07-24}.
Alessandro Rubini's avatar
Alessandro Rubini committed

The EEPROM content that has been read at initialization time
is still available to sub-drivers after they are loaded, but a
sub-driver cannot write to the EEPROM using carrier methods.
The carrier refuses to act on
registers after the golden gateware is replaced by a new 
mezzanine-specific binary,
which by definition is unknown to the carrier itself.

@b{Note:} currently the SPEC driver does not re-write the golden
binary file when the sub-driver releases control of the card. This
allows a further driver to make use of an existing binary, and may be
@c ==========================================================================
@node SPEC Module Parameters
@section SPEC Module Parameters

The module can receive the following parameters to customize its operation:

@table @code

@item fw_name

	This string parameter can be used to override the default name
        (@code{fmc/spec-init.bin}) for the initialization binary file.

@item use_msi

	This forces the driver to use @i{message signalled interrupts}.
        MSI interrupts have some advantages over conventional wire-level
        interrupts, but with the GN4124 we had serious issues. See
        @ref{Interrupts in spec.ko} for details.
        By default the driver uses the old-fashioned wire-level
        signalling method; to experiment with MSI pass @code{use_msi=1} .
	If not zero, this parameter requests to self-test interrupt
        generation, using the software-driven interrupt source in
        Gennum registers. This usually does not
        work on my host if I use MSI,
        for yet unknown reasons (and that's why it is
        disabled by default).

@item i2c_dump

	If not zero, this parameter requests to @i{printk} the content
        of the FMC eeprom, for diagnostic purposes.

@item show_sdb

	If not zero, the SDB internal structure of the golden binary
        is reported through kernel messages. It is disabled by default.

Any mezzanine-specific action must be performed by the driver for the
specific FMC card, including reprograming the FPGA with the final
gateware file.  Similarly, the @i{spec} driver is not concerned with
programming the LM32 image, when it makes sense to. This is different
from the role splitting in previous versions of the driver.
Alessandro Rubini's avatar
Alessandro Rubini committed

@b{Note:} the gateware binary is looked-for in @i{/lib/firmware/fmc},
which is where all fmc-related external files are expected to live.
That's because our own installations share firmware for COTS peripherals
but mount a host-specific NFS subdirectory.
Alessandro Rubini's avatar
Alessandro Rubini committed

Please refer to the @i{fmc-bus} document for details about the overall
design of the interactions of carriers and mezzanines.
@b{Warning:} currently the @i{match} function of the bus always
returns success: the mezzanines I currently have for testing have no
ID records written in their internal EEPROM, so I'm not able to setup
the associated data structures and code.  For this reason there is no
@i{module_alias} support nor autoprobe of drivers: any @i{fmc} driver
you load will drive all SPEC cards found on the system unless it
limits itself through parameters (see below)

@c ==========================================================================
@node Sub-Module Parameters
@section Sub-Module Parameters

Most of the FMC drivers, also called sub-modules, need the same
set of kernel parameters, this package includes support
to implement common parameters, by means of fields
in the @code{fmc_driver} structure and simple macro definitions.

The parameters are carrier-specific, in that they rely on the @i{busid}
concept, that varies among carriers (here it is a PCI bus-devfn number).
Drivers for other carriers will most likely offer something similar
but not identical to this; some code duplication is unavoidable.

This is the list of parameters, to see how they are used in sub-modules,
please look at @i{spec-trivial.c}.

@table @code

@item busid=

	This is an array of integers, specifying the PCI bus and PCI devfn,
        each of the fields being 8 bits (and the latter is most likely 0).
        For example: @code{0x0400} (bus 4,
        slot 0).  If any such ID is specified, the sub-driver will only
        accept to drive cards that appear in the list (even if the
        FMC ID matches).

@item gateware=

	The argument is an array of strings. If no @i{busid=} is
        specified, the first string of @i{gateware=} is used for
        all cards; otherwise the identifiers and gateware names are
        paired one by one, in the order specified.
@item show_sdb=

	For modules supporting it, this parameter asks sub-modules to
        show the SDB internal structure to kernel messages. It is
        disabled by default because those lines tend to hide more
        important messages when you look at the system console while
        loading the drivers.

@end table

For example, if you are using the trivial driver to load two different
gateware files to two different cards, you can use the following
parameters to load different binaries to the cards, after looking up
the PCI identifiers:

@smallexample
   insmod fmc-trivial.ko \
                         busid=0x0200,0x0400 \
                         gateware=fmc/fine-delay.bin,fmc/simple-dio.bin
@end smallexample
Please note that not all sub-modules support all of those parameters.
You can use @i{modinfo} to check what is supported by each module.

@c ==========================================================================
@node Interrupts in spec.ko
@section Interrupts in spec.ko

Up to version 2.0 of this package, I enabled MSI (@i{message signalled
interrupts}) in the Gennum chip.  Now the default is using normal
@i{wire-level} PCI interrupts; there is a module parameter called
@code{use_msi} for those who want to experiment with MSI.

Unless you want to help with making MSI work, you are not interested
in this section, and you can skip over it.

@sp 1

While MSI should perform better than conventional interrupts, there's
a misbehaviour in the GN4124 that makes their use pretty difficult.

The @i{message} in MSI includes a data field, chosen by the operating
system for its own use.  Linux stores the so-called @i{vector number}
in the data field, which is an index in an kernel-internal array.  The
PCI-E standards allows for peripheral devices to support several MSI
signals, if the operating system enables them to do so; the Gennum
chip supports this, and is able to fire 4 different MSI signals,
however, it is not able to send the base MSI signal if the
multiple-MSI feature is kept disabled.

The 4124 is found to choose the MSI interrupt to send according to the
two least significant bits of the data field.  For this reason, we
must enable the multiple-MSI feature, and enable in the chip
the corresponding interrupt configuration register.  The former
operation involves a standard registers, the latter is Gennum-specific.

Linux, however, does not know that multiple-MSI is enabled, and thus
it configures the standard register for a single MSI.  When this
happens, interrupts stop working (because the Gennum would send msi 2,
for example, but only msi 0 is enabled).

The code of this package, under ``@code{if (use_msi)}'' stanzas, fixes
the control register after Linux touches it, but it may not be enough.
We found, for example, that the @i{irqbalance} tool (which is
installed and runs in background in a number of recent installations)
will make some configuration attempt after interrupts starts to flow.
When this happens, Linux will rewrite the control register thus
disabling SPEC interrupts.  Killing @i{irqbalance} in advance was
found to fix the problem, but clearly this isn't production-ready.
@b{Note:} Linux doesn't currently support enabling multiple-MSI unless
they are MSI-X (a further standard) so we can't just enable all 4 of
them.

If you want to help with taming the MSI problem, you should load the
@i{spec} driver with @code{use_msi=1} and run the @i{wr-nic}
driver. If you are unable to exchange frames, or data transfer just
stops, please grep for @code{wr-nic} in @file{/proc/interrupts} to see
if the counters are moving or not.  If not, the problem is most likely
in register 0x4a (@code{MSI_CONTROL}) that lost its correct value of
@code{0xa5}. You can check the high 16 bits in the output of
@code{specmem -g 48} to verify.  To unlock the situation, you need to
fix this register and force an edge in the interrupt line from the
FPGA to the Gennum, by acting on VIC registers. The ``magic'' sequence
is the same you find at the end of @code{wrn_handler()}, in
@file{wr-nic-eth.c}.

@sp 1

The following snapshot come from a system with two SPEC cards
plugged. No @i{irqbalance} is running and both kind of interrupts
work. With non-msi interrupts, the lines are shared with other
peripherals, and you'll see something like this:
@smallexample
  spusa.root# grep nic /proc/interrupts
   16:    236      0   0   805   IO-APIC-fasteoi   snd_hda_intel, wr-nic
   18:      0  14721  16    33   IO-APIC-fasteoi   ahci, ohci_hcd:usb4, wr-nic
@end smallexample

If you enable MSI, interrupts have higher numbers, allocated specifically
for the peripheral:

@smallexample
  spusa.root# grep wr-nic /proc/interrupts
   47:      0      0   0   124   PCI-MSI-edge  wr-nic
   48:  70470      0   0    26   PCI-MSI-edge  wr-nic
@c ##########################################################################
@node fmc-trivial.ko
@chapter fmc-trivial.ko
Alessandro Rubini's avatar
Alessandro Rubini committed

The simple module @i{fmc-trivial} is just a simple client that
registers an interrupt handler. I used it to verify the basic mechanism
of the FMC bus and how interrupts worked.
The module implements the generic SPEC parameters, so it can program a
different gateware file in each card. The whole list of parameters it
accepts are:
@table @code

@item busid=
@itemx gateware=
      Generic parameters. See @ref{Sub-Module Parameters}.

@c no docbook is generated, so the following is like "#if 0"
@ifdocbook
@item sdb=

	This is an array of integers, specifying the @i{sdb}
        starting address after programming the gateware. See
        @ref{Sub-Module Parameters} about how this is used in multi-board
        environments.
       
@item lm32=

	This is a array of strings like @code{gateware=},
        listing the name or names
        to be used to reprogram the internal LM32. The same rules as for
        @code{gateware=} above are used for matching binaries and cards.
        The carrier will copy the @i{lm32} executable to the first
        SDB record that is mapped as ``@code{WB4-BlockRAM}'' (thus,
        it needs the @code{sdb=} values to be specified.
@end ifdocbook
@end table

This driver is worth reading, but it is not worth describing here.
@c ##########################################################################
@node fmc-write-eeprom.ko
@chapter fmc-write-eeprom.ko
This module is designed to load a binary file from @i{/lib/firmware}
and to write it to the internal EEPROM of the mezzanine card. This
driver uses the @code{busid} generic parameter, but doesn't use the
other ones (even if @i{modinfo} reports them).
Overwriting the EEPROM is not something you should do daily, and it is
expected to only happen during manufacturing. For this reason, the
module makes it unlikely for the random user to change a working EEPROM.

The module takes the following measures:

@itemize @bullet

@item It accepts a @code{file=} argument (within @i{/lib/firmware})
and if no such argument is received, it doesn't write anything
(i.e. there is no default file name)

@item If the file name ends with @code{.bin} it is written verbatim
starting at offset 0.

@item If the file name ends with @code{.tlv} it is interpreted as
type-length-value (i.e., it allows @i{writev(2)}-like operation).

@item If the file name doesn't match any of the patterns above, it is
ignored and no write is performed.

@item Only cards listed with @code{busid=} are written to. If no
@i{busid} is specified, no programming is done (and the probe function
of the driver will fail).

@end itemize

Each TLV tuple is formatted in this way: the header is 5 bytes,
followed by data. The first byte is @code{w} for @i{write}, the
next two bytes represent the address, in little-endian byte order, and
the next two represent the data length, in little-endian order. The length does
not include the header (it is the actual number of bytes to be
written).

This is a real example: that writes 5 bytes at position 0x110:

@smallexample
   spusa.root# od -t x1 -Ax /lib/firmware/try.tlv
   000000 77 10 01 05 00 30 31 32 33 34
   00000a
   spusa.root# insmod /tmp/fmc-write-eeprom.ko busid=0x0200 file=try.tlv
   [19983.391498] spec 0000:03:00.0: write 5 bytes at 0x0110
   [19983.414615] spec 0000:03:00.0: write_eeprom: success
@end smallexample
Please note that you'll most likely want to use SDBFS to build your
EEPROM image, at least if your mezzanines are being used in the White Rabbit
environment. For this reason the TLV format is not expected to be used much
and is not expected to be developed further.

@c ##########################################################################
@node The WR-NIC
@chapter The WR-NIC

With the current code base, the @code{wr-nic.ko} driver is designed
to run with the simple 5-Channel @i{simple-DIO} mezzanine board,
because it includes both
code to access the network card and code to act on the DIO channels,
using time tags that are provided by the @i{White Rabbit} mechanism.
Similarly, both incoming and outgoing frames can be time-stamped by

This driver is the most important driver in this package: it is
a generic implementation of the @i{spec-sw} framework which can be
useful by itself as a White Rabbit starter kit.  Moreover, it is a
complete driver that can serve as a model for other developments.

Within @i{White Rabbit} we have other full-featured drivers for
specialized FMC mezzanines hosted on the SPEC carrier. They are not
part of this package because of their specialized nature; all of them
are nonetheless hosted on @url{www.ohwr.org}, usually as a
@i{software} subproject of the related gateware project.

@c ==========================================================================
@node Code Layout
@section Code Layout

This section is mainly for the developers who look in the code, and for
me to make order in my own mind. SPEC users are expected to skip to
the next section.

The @code{wr-nic.ko} is built using a number of headers and source files,
spread over several directories:

@table @file

@item wbgen-regs/

	The directory hosts the register definitions for the various
        core that are included in the FPGA binary. The headers are
        generated by running @i{wbgen2} over the @code{.wb} files that
        are part of the VHDL source repositories; unfortunately some
        minor editing is needed on the @i{wbgen2} output, so there
        is a @code{Makefile} that takes care of this.  This package
        includes both the input file and the output header; the log
        messages details the upstream origin of each @code{.wb} file.
        The directory started out as a direct copy of the directory
        with the same name found in @code{wr-switch-sw}, release 3.0.

@item wr_nic/

	The directory started out as an unchanged copy of the driver
        used in the @code{wr-switch-sw} package, release 3.0. The directory
        name is the same in both projects. All later
        commits take care of differences in the SPEC with regard to the
        switch, but we plan to clean up those later changes and reach
        a unified code base between the White Rabbit switch and the White
        Rabbit node. The NIC driver itself is a @i{platform driver},
        instantiated by @i{platform devices} defined externally.

@end table

The @i{wr-nic} driver refers to several headers, in addition to the
register definitions. This is the role of each of them:

@table @file

@item include/linux/fmc.h
@itemx include/linux/sdb.h
@itemx include/linux/fmc-sdb.h

	These three headers are used to define the interface to the
        FMC bus abstraction and the SDB self-description of the
	internal FPGA bus. They are used by other @i{spec-sw} files as well.
        We include them as @code{<linux/fmc.h>} because we plan to
        have them upstreamed to the official kernel, and we don't want to
        introduce incompatibilities in the related source files.

@item wr_nic/nic-mem.h
@itemx wr_nic/nic-hardware.h
@itemx wr_nic/wr-nic.h

	These headers come from @i{wr-switch-sw/wr_nic} with minor
        SPEC-related modifications. @i{nic-mem.h} defines the memory map and
        is now almost obsoleted by SDB; @i{nic-hardware.h} is a collection
        of inline functions used by the driver; @i{wr-nic.h} defines
        all the important data structures and @i{ioctl} commands. Because
        of @i{ioctl} commands, it has a rather generic name and
        is meant to be included by user space as well as kernel space.

@item spec.h

	Definitions related to the SPEC carrier (Gennum registers and
        other SPEC-internal stuff).  It is currently used by
        @i{wr-nic-eth.c}, which is not completely carrier-independent.

@item spec-nic.h

	The header defines the SDB vendor and device values used in
        @i{wr-nic} as well as the data structures and prototypes used
        internally by the driver.

@item wr-dio.h

	The header hosts the user interface to access the DIO channels.
        It is included by @i{wr-nic-dio.c} as well as the user-space
        tools that want to configure DIO operation.

@end table

The source code of the driver itself is split in several files, in addition
to the NIC platform driver hosted in @file{wr_nic/}:

@table @file

@item wr-nic-core.c

	The file is the @i{fmc} driver: it implements the @i{probe}
        and @i{remove} methods and deals with loading the firmware
        file and the LM32 program binary (called @i{wrc}: White Rabbit
        Core).

@item wr-nic-eth.c

	This is concerned with creating the platform device for the
        network interface card. It maps the needed device memory, allocates
        the platform data and sets up the internal interrupt controller
        to route interrupts to the platform driver.

@item wr-nic-dio.c

	This is the mezzanine-specific driver. It implements the
        @i{ioctl} commands that allow user space to talk with
        the mezzanine. It only implements the @i{ioctl} method
        and support functions for it (e.g., interrupt management).
        If you want to port  @i{wr-nic} to a different mezzanine, this
        is the file you need to replace.

@end table

@c ==========================================================================
@node Overview of the Driver
@section Overview of the Driver

The @i{wr-nic} driver is basically an Ethernet driver with support for
hardware time stamping.  The @i{simple-DIO} mezzanine card can be used by means
of @i{ioctl} commands. Such commands are designed to be portable, so
user-space programs should able to identify which mezzanine is
connected to the SPEC network card and act accordingly.

The driver loads two binaries, using the @i{firmware loader} mechanism
offered by the Linux kernel: one is the gateware file, that is requested
through the @i{reprogram} carrier method; the other is the LM32 program
binary, which however is only loaded on user request. With the
current version of the gateware binary, the LM32 program is already included
in its most current version, so you won't need to load it.

The default file names are as follows:

@table @file

@item fmc/wr_nic_dio.bin

	This is the @i{gateware} file. The default name can be changed
        using the @code{file=} module parameter.

@item fmc/wr_nic_dio-wrc.bin

	This is the LM32 program file, or @i{White Rabbit Core}, WRC.
        The file is not loaded automatically, because we expect to deliver
        a gateware file that already includes the correct LM32 program
        (but the binary currently suggested does not include it).
        To request loading the file you should pass @code{wrc=1}. To
        request loading a different WRC file name, you should pass
        the actual file name. For example ``@code{wrc=recompiled-wrc.bin}''.

@end table

The binaries suggested for this software release are available from
the @i{files} tab of the Open Hardware Repository. The direct
links are as follows (the former is required, the latter is optional):
http://www.ohwr.org/attachments/download/1633/wr_nic_dio.bin-2012-10-02
http://www.ohwr.org/attachments/download/1611/wr_nic_dio-wrc.bin-2012-09-26
@end example

The date is included in the binary name so we won't need to remove the
binaries when they are obsoleted by newer ones:
@i{spec-sw} releases are expected to continue working in the
future, and if you are using this version you need those very files.
You can copy the following command sequence to your shell
in order to fill your @file{/lib/firmware/fmc} with everything that's
needed to run @i{wr-nic}:

@smallexample
cd /tmp
wget -O wr_nic_dio.bin \
   http://www.ohwr.org/attachments/download/1633/wr_nic_dio.bin-2012-10-02
wget -O wr_nic_dio-wrc.bin \
   http://www.ohwr.org/attachments/download/1611/wr_nic_dio-wrc.bin-2012-09-26
sudo mv wr_nic_dio wr_nic_dio-wrc /lib/firmware/fmc
@end smallexample

@c ==========================================================================
@node Controlling the White Rabbit Core
@section Controlling the White Rabbit Core

In this release the driver is not controlling the White Rabbit Core
and the default mode of operation is @i{slave}.  You can
use the serial port and interact with the WRC shell to change the
operation mode and do other supported interaction with the PTP daemon.
If you want, you can use the serial port to configure a card as
@i{free running master} storing such request in EEPROM to make it
persistent.

The complete reference of the shell commands is included in the
@i{wrpc-sw} manual in the @i{files} tab of the project.  The direct
link is
@url{http://www.ohwr.org/attachments/download/1586/wrpc-v2.0.pdf}.

The most useful commands are repeated here for your convenience

@table @code

@item mode grandmaster
@itemx mode master
@itemx mode slave

	The commands change the current PTP mode. @code{mode}
        with no arguments reports the current mode.

@item ptp stop
@itemx ptp start

	Stop and start the daemon running on LM32. You'll most likely
        need to stop and restart the PTP daemon after changing mode.

@item time raw

	Prints the internal device time as seconds and nanoseconds.

@item gui

	Start a self-refreshing informative display of the @i{White Rabbit}
        synchronization status. Press @code{<ESC>} to return to
        command-line mode.

@item mac get

	Reports the MAC address used by WRPC (it should match what is
        reported by @code{ifconfig} in Linux.

@end table

Please note that you may also need to configure the SFP module
you are using, with the @code{sfp} WRC command, as described in the
@code{wrc-v2.0.pdf} manual referenced above.

@c ==========================================================================
@node Transferring Data
@section Transferring Data

The @i{wr-nic} driver registers a Linux network interface card for
each SPEC device it drives.  The cards are called @code{wr%d} (i.e.,
@i{wr0}, @i{wr1}, ...).

The MAC address of the device is retrieved from the internal @i{White
Rabbit} registers, because at the time when Linux configures the
interface the WRC code has already configured the Ethernet port and
generated a valid 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 to be able to use it to transfer data. Note however
that @i{White Rabbit} synchronization happens even if the interface
is not configured in Linux.  In case you need to change the MAC
address as seen by Linux, the command to type is something like the
following:

@example
   ifconfig wr0 hw ether 12:34:56:78:9a:bc
@end example
The fiber controlled by the SPEC can carry normal data traffic in
addition to the PTP frames of @i{White Rabbit}, that remain
invisible to the host computer. The
examples related to the @i{simple DIO} device use this data channel
to exchange Ethernet frames so you'll need to assign IP addresses to
your @i{wr} interfaces.

@c ==========================================================================
@node Timestamping Frames
@section Timestamping Frames

The SPEC Ethernet interface
supports hardware timestamping for user frames through the
standard Linux mechanisms.  Time stamps are currently reported with
a resolution of 8ns only (@i{White Rabbit} does much better, but
we don't have the code in place for this demo, yet).

Unfortunately the Linux mechanisms are not trivial: the application must
enable timestamping on both the hardware interface and the specific
socket it is using, and it must issue several @i{ioctl} and @i{setsockopt}
commands. Moreover, timestamps are returned to user space using the
@i{recvmsg} system call, which is more difficult to deal with than the
normal @i{send} or @i{recv}.

To simplify use of timestamps for Ethernet frames, 
this package includes the @file{stamp-frame} program in the
@file{tools} directory.  The leading part of its source
file includes generic library-like functions that deal with the
intricacies of timestamping; the final part is the actual example,
which is designed to be simple and readable.

The program is a minimal implementation of the basic
time-synchronization protocols (like NTP and PTP), but excluding the
synchronization itself. The idea is sending a frame from one host to
another, and receiving a second frame back; the departure and arrival
times are recorded and collected at a single place, so they can
be reported to
the user.

The @file{stamp-frame} example supports two modes of operations. In
@i{listen} mode, it binds to an Ethernet interface and listens forever:
it waits for the forward frames and replies to them; in normal mode it
sends the forward frame and reports data as soon as it gets a reply.  This is
an example running on two different hosts:

@smallexample
   tornado.root# stamp-frame wr0 listen
   stamp-frame: Using interface wr0, with all timestamp options active

   spusa.root# stamp-frame wr1
   stamp-frame: Using interface wr1, with all timestamp options active
   timestamp    T1:      1476.381349032
   timestamp    T2:      1476.381403352
   timestamp    T3:      1476.391563248
   timestamp    T4:      1476.391617560
   round trip time:         0.000108632
   forward    time:         0.000054320
   backward   time:         0.000054312
@end smallexample

The four times are departure and arrival of the forward frame, followed
by departure and arrival of the backward frame. Thus,
time stamps T1 and T4 are collected at the
original sender (here: @i{spusa}) while T2 and T3 are collected at the
remote host (here: @i{tornado}).  The times above are all consistent
because the two SPEC cards are synchronized with @i{White Rabbit}. The
reported forward and backward times match the fact that I used
a 10km fiber to connect the two cards; the difference between them
is due to the different speed of light in the two directions,
because the two SFP transceivers I plugged use different wave lengths.

The following example shows the output for two forcibly-unsynchronized
cards.  The difference between the two clocks is clearly a
few seconds; the
@i{round trip time} is correct nonetheless, because it is a difference of
differences:

@smallexample
   timestamp    T1:        13.225249168
   timestamp    T2:         9.130237600
   timestamp    T3:         9.140438816
   timestamp    T4:        13.235559016
   round trip time:         0.000108632
   forward    time:        -5.904988432
   backward   time:         4.095120200
@end smallexample
The code in @file{stamp-frame}
is designed to be simple to be reused, but there is one non-obvious detail
that is worth describing here.  Whereas the receive timestamp is
returned to user-space together with the frame it refers to, the
transmit timestamp is only known after the relevant frame left the
computer.  For this reason, in order
to communicate the TX timestamp of a frame to your peer, you'll need to
send another message which carries the departure time of the previous
frame.  This further message is usually called @i{follow-up},
and @file{stamp-frame} respects this tradition.

@c ==========================================================================
@node Accessing the DIO Channels
@section Accessing the DIO Channels

In order to access the DIO channels, user-space programs are expected
to issue device-specific @i{ioctl} commands.  The driver supports two
commands, allocated at the end of the range of command numbers reserved
for device-specific use:

@table @code

@item PRIV_MEZZANINE_ID

	The command is used to identify the features of the
        specific NIC device.  It tells user space which mezzanine is
        currently plugged and also which type of carrier you are talking to.
        The command exchanges a data structure with user space in order
        to be able to extend its functionality over time, and such data
        structure includes  a sub-command
        field. (For example, we may return EEPROM contents to user space
        on request).

        @b{Warning}: the command is not implemented because we still have
        no mezzanine identification in place. The error being returned
        is @code{EAGAIN}; user code can rely on that error to know it
        is actually talking with a SPEC device, even if no identification
        is currently possible.

@item PRIV_MEZZANINE_CMD

	The command is based on the exchange of a data structure: by
        means of sub-commands included in such structure user space
        programs can request different services to the mezzanine driver.
        In the case of the DIO mezzanine this includes generating pulses
        and timestamping input events; other mezzanine drivers will
        be able to use the command in a different way. The application
        is expected to first run @code{PRIV_MEZZANINE_ID} to ensure the
        NIC device is connected to the right mezzanine.

@end table

In the specific case of this @i{wr-nic} driver, the data structure
is defined and explained in @code{wr-dio.h} and is not repeated here.

The structure includes a few integer fields and an array of
@code{struct timespec}.  Such structures define time stamps with
nanosecond precision, but the @i{simple-DIO} mezzanine and its gateware
are able to time-stamp input events and generate output events with a
resolution of 8ns.

When the device is asked to timestamp input events, the array of
@code{struct timespec} is used
to return such events to user space.  When the device is asked to
generate output pulses at specific points in time, the array is used
to pass three values: the beginning of the pulse, the duration of the
pulse and (optionally) the period of the pulse train.

Specifics about the use of individual fields are shown in the header
(in a big comment block), in the driver itself and in the user-space
programs that call @i{ioctl}.

In lab environments you may be concerned about the duration of the
@i{ioctl} implementation, because it sometimes seems to do more work
than needed. To verify whether we have an over-engineering problem in
kernel space, I provided a simple measurement of how much time is
spent in the @i{Ioctl} itself. The @i{make} variable
@code{WR_NIC_CFLAGS} can be used to pass extra flags to the compiler,
and the macro @code{DIO_STAT} enables the time measurement.
Compiling with the following command thus enable such measurement
and associated @i{printk} -- the time is usually 5 microseconds for me:

@example
   make WR_NIC_FLAGS=-DDIO_STAT
@end example
Previous versions of this manual described how to command pulses on
several channels with a single @i{ioctl} command, but that feature has
never been implemented (one of the reasons is that @i{ioctl} revealed
fast, so calling it several times is acceptable).

@c ==========================================================================
@node WR-NIC Command Tool

In the @file{tools/} subdirectory of this project, you find the
@file{wr-dio-cmd} program, which is a command-line interface to the
@i{ioctl} command that acts on the @i{simple-DIO} mezzanine card.  Other
@code{wr-dio-} tools are provided (and described below) but this is
the most generic one.
Please note that neither timestamping nor pulse generation work
if the WR core is not running or has an invalid time: it must either be
a master or a synchronized slave.

Moreover, please note that this tool is just a demonstration to quickly
test the I/O features of the device (and for me to verify the kernel
part is actually working): for serious use you should call
@i{ioctl} by yourself with proper arguments, and avoid all the parsing
of ASCII and repeated invocation of this program.

This is the general syntax of the command:

@example
   wr-dio-cmd <ifname> <cmd> [<arg> ...]
@end example

The arguments have the following meaning

@table @code
@item ifname

	The name of the network interface, most likely @code{wr0}
        (if you have more than one SPEC card, the other interfaces are
        called @code{wr1}, @code{wr2} and so on).
	The specific command. Supported commands are listed below.
        Each command takes zero or more of arguments. If you pass
        a wrong number of arguments you'll get help, and
        if one argument is wrong (e.g., not a number) the
	error message is meant to be directly helpful.
The current version of the tool supports the following commands:

@table @code
@item stamp [<channel>] [wait]
@itemx stampm [<channel-mask>]