Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC Bus
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
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 Bus
Commits
14a7b580
Commit
14a7b580
authored
Jan 14, 2013
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fmc.h and docs: new fields (yet unused) in fmc_device
Signed-off-by:
Alessandro Rubini
<
rubini@gnudd.com
>
parent
279c21b6
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
93 additions
and
32 deletions
+93
-32
fmc-bus.in
doc/fmc-bus.in
+78
-27
fmc.h
kernel/include/linux/fmc.h
+15
-5
No files found.
doc/fmc-bus.in
View file @
14a7b580
...
...
@@ -34,7 +34,7 @@
@
setchapternewpage
off
@
set
update
-
month
November
2012
@
set
update
-
month
January
2013
@
finalout
...
...
@@ -99,7 +99,7 @@ Trade Association} and ratified by ANSI, the American National
Standard
Institute
.
The
official
documentation
is
called
``
ANSI
-
VITA
57.1
''
.
The
@
sc
{
fmc
}
card
is
an
almost
square
@
sc
{
psb
},
around
70
x75
millimet
er
s
,
that
The
@
sc
{
fmc
}
card
is
an
almost
square
@
sc
{
psb
},
around
70
x75
millimet
re
s
,
that
is
called
@
i
{
mezzanine
}
in
this
document
.
It
usually
lives
plugged
into
into
another
@
sc
{
psb
}
for
power
supply
and
control
;
such
bigger
circuit
board
is
called
@
i
{
carrier
}
from
now
on
,
and
a
single
carrier
...
...
@@ -158,8 +158,11 @@ to work, and a few more:
@smallexample
int fmc_driver_register(struct fmc_driver *drv);
void fmc_driver_unregister(struct fmc_driver *drv);
int fmc_device_register(struct fmc_device *tdev);
void fmc_device_unregister(struct fmc_device *tdev);
int fmc_device_register(struct fmc_device *fmc);
void fmc_device_unregister(struct fmc_device *fmc);
int fmc_device_register_n(struct fmc_device *fmc, int n);
void fmc_device_unregister_n(struct fmc_device *fmc, int n);
uint32_t fmc_readl(struct fmc_device *fmc, int offset);
void fmc_writel(struct fmc_device *fmc, uint32_t val, int off);
...
...
@@ -167,9 +170,21 @@ to work, and a few more:
void fmc_set_drvdata(struct fmc_device *fmc, void *data);
@end smallexample
They should be self-explicative, so nothing is added here. The data
structure that describe a device is detailed in @ref{FMC Device},
the one that describes a driver is detailed in @ref{FMC Driver}.
The data structure that describe a device is detailed in @ref{FMC
Device}, the one that describes a driver is detailed in @ref{FMC
Driver}.
The functions to register and unregister @i{n} devices are meant to be
used by carriers that host more than one mezzanine. The devices must
be all registered at the same time because if the @sc{fpga} is
reprogrammed, all devices in the array are affected. Usually, the
driver matching the first device will reprogram the @sc{fpga}, so
other devices must know they are already driven by a reprogrammed
@sc{fpga}.
If a carrier hosts slots that are driven by different @sc{fpga} devices,
it should register as a group only mezzanines that are driven by the same
@sc{fpga}, for the reason outlined above.
@c ##########################################################################
@node FMC Device
...
...
@@ -212,35 +227,71 @@ struct fmc_device {
struct
fmc_operations
*
op
;
/*
carrier
-
provided
*/
int
irq
;
/*
according
to
host
bus
.
0
==
none
*/
int
eeprom_len
;
/*
Usually
8
kB
,
may
be
less
*/
int
eeprom_addr
;
/*
0x50
,
0x52
etc
*/
uint8_t
*
eeprom
;
/*
Full
contents
or
leading
part
*/
char
*
carrier_name
;
/*
"SPEC"
or
similar
,
for
special
use
*/
void
*
carrier_data
;
/*
"struct spec *"
or
equivalent
*/
__iomem
void
*
base
;
/*
May
be
NULL
(
Etherbone
)
*/
__iomem
void
*
fpga_base
;
/*
May
be
NULL
(
Etherbone
)
*/
__iomem
void
*
slot_base
;
/*
Set
by
the
driver
*/
struct
fmc_device
**
devarray
;
/*
Allocated
by
the
bus
*/
int
slot_id
;
/*
Index
in
the
slot
array
*/
int
nr_slots
;
/*
Number
of
slots
in
this
carrier
*/
unsigned
long
memlen
;
/*
Used
for
the
char
device
*/
struct
device
dev
;
/*
For
Linux
use
*/
struct
device
*
hwdev
;
/*
The
underlying
hardware
device
*/
unsigned
long
sdbfs_entry
;
struct
sdb_array
*
sdb
;
uint32_t
device_id
;
/*
Filled
by
the
device
*/
char
*
mezzanine_name
;
/*
Built
by
fmc
-
core
(
allocated
)
*/
char
*
mezzanine_name
;
/*
Defaults
to
``
fmc
''
*/
void
*
mezzanine_data
;
};
@
end
smallexample
The
meaning
of
most
fields
is
summarized
in
the
code
comment
above
.
All
of
the
fields
must
be
filled
by
the
carrier
driver
before
registration
,
with
a
few
exceptions
.
Please
note
that
@
i
{
hwdev
}
is
used
for
messages
:
the
core
calls
@
code
{
dev_err
()}
and
similar
functions
,
so
the
field
must
be
properly
set
or
the
system
will
@
i
{
Oops
}
with
a
NULL
pointer
pretty
soon
.
Similarly
,
the
carrier
should
read
its
own
@
sc
{
eeprom
}
memory
before
registering
the
driver
.
The
fields
that
are
not
set
by
the
carrier
are
:
@
i
{
fmc_fru_id
}
and
@
i
{
mezzanine_name
}
(
both
are
set
by
the
bus
core
according
to
@
sc
{
eeprom
}
contents
);
@
i
{
sdbfs_entry
}
(
autodetected
by
the
core
while
scanning
the
@
sc
{
eeprom
};
@
i
{
sdb
}
(
built
when
scanning
the
@
sc
{
fpga
}
contents
)
and
@
i
{
mezzanine_data
}
(
private
to
the
mezzanine
driver
).
The
meaning
of
most
fields
is
summarized
in
the
code
comment
above
.
The
following
fields
must
be
filled
by
the
carrier
driver
before
registration
:
@
itemize
@
bullet
@
item
@
t
{
version
}:
must
be
set
to
@
t
{
FMC_VERSION
}.
@
item
@
t
{
owner
}:
set
to
@
t
{
MODULE_OWNER
}.
@
item
@
t
{
op
}:
the
operations
to
act
on
the
device
.
@
item
@
t
{
irq
}:
number
for
the
mezzanine
;
may
be
zero
.
@
item
@
t
{
eeprom_len
}:
length
of
the
following
array
.
@
item
@
t
{
eeprom_addr
}:
0x50
for
first
mezzanine
and
so
on
.
@
item
@
t
{
eeprom
}:
the
full
content
of
the
@
sc
{
i2c
}
@
sc
{
eeprom
}.
@
item
@
t
{
carrier_name
}.
@
item
@
t
{
carrier_data
}:
a
unique
pointer
for
the
carrier
.
@
item
@
t
{
fpga_base
}:
the
I
/
O
memory
address
(
may
be
NULL
).
@
item
@
t
{
slot_id
}:
the
index
of
this
slot
(
starting
from
zero
).
@
item
@
t
{
memlen
}:
if
@
t
{
fpga_base
}
is
valid
,
the
length
of
I
/
O
memory
.
@
item
@
t
{
hwdev
}:
to
be
used
in
@
i
{
dev_err
()}
calls
.
@
item
@
t
{
device_id
}:
a
slot
-
specific
unique
integer
number
.
@
item
@
t
{
mezzanine_name
}:
used
as
name
for
the
Linux
device
structure
.
@
end
itemize
Please
note
that
the
carrier
should
read
its
own
@
sc
{
eeprom
}
memory
before
registering
the
device
,
as
well
as
fill
all
other
fields
listed
above
.
The
following
fields
should
not
be
assigned
,
because
they
are
filled
later
by
either
the
bus
or
the
device
driver
:
@
itemize
@
bullet
@
item
@
t
{
flags
}.
@
item
@
t
{
fru_id
}:
filled
by
the
bus
,
parsing
the
eeprom
.
@
c
FIXME
@
item
@
t
{
slot_base
}:
filled
and
used
by
the
driver
,
if
useful
to
it
.
@
item
@
t
{
devarray
}:
an
array
og
all
mezzanines
driven
by
a
singe
@
sc
{
fpga
}.
@
item
@
t
{
nr_slots
}:
set
by
the
core
at
registration
time
.
@
item
@
t
{
dev
}:
used
by
Linux
.
@
item
@
t
{
sdb
}:
@
sc
{
fpga
}
contents
,
scanned
according
to
driver
's directions.
@item @t{sdbfs_entry}: @sc{sdb} entry point in @sc{eeprom}: autodetected.
@item @t{mezzanine_data}: available for the driver.
@end itemize
@b{Note}: @i{mezzanine_data} may be redundant, because Linux offers
the @i{drvdata} approach, so the field may be removed in later
...
...
@@ -284,10 +335,10 @@ The individual methods perform the following tasks:
These functions access @sc{fpga} registers by whatever means the
carrier offers. They are not expected to fail, and most of the time
they will just make a memory access to the host bus. If the
carrier
provides
a
@
i
{
base
}
pointer
,
the
driver
may
use
direct
carrier provides a @i{
fpga_
base} pointer, the driver may use direct
access through that pointer. For this reason the header offers
the inline functions @i{fmc_readl} and @i{fmc_writel} that
access
@
i
{
base
}
if
the
respective
method
is
NULL
.
A
driver
that
access @i{
fpga_
base} if the respective method is NULL. A driver that
wants to be portable and efficient should use @i{fmc_readl}
and @i{fmc_writel}.
For Etherbone, or other non-local carriers,
...
...
@@ -547,10 +598,10 @@ the latter technique is used when the @sc{fpga} is already programmed
when the device is registered to the bus core.
In some special cases it is possible for a driver to directly access
@
sc
{
fpga
}
registers
,
by
means
of
the
@
code
{
base
}
field
of
the
device
@sc{fpga} registers, by means of the @code{
fpga_
base} field of the device
structure. This may be needed for high-bandwidth peripherals like fast ADC
cards. If the @i{device} module registered a remote device (for example
by
means
of
Etherbone
),
the
@
code
{
base
}
pointer
will
be
NULL
.
by means of Etherbone), the @code{
fpga_
base} pointer will be NULL.
Therefore, drivers must be ready to deal with NULL base pointers, and
fail gracefully. Most driver, however, are not expected to access
the pointer directly but run @i{fmc_readl} and @i{fmc_writel} instead,
...
...
kernel/include/linux/fmc.h
View file @
14a7b580
...
...
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/io.h>
...
...
@@ -23,7 +24,7 @@ struct fmc_driver;
* to check the version of the data structures we receive.
*/
#define FMC_MAJOR
2
#define FMC_MAJOR
3
#define FMC_MINOR 0
#define FMC_VERSION ((FMC_MAJOR << 16) | FMC_MINOR)
#define __FMC_MAJOR(x) ((x) >> 16)
...
...
@@ -157,17 +158,22 @@ struct fmc_device {
struct
fmc_operations
*
op
;
/* carrier-provided */
int
irq
;
/* according to host bus. 0 == none */
int
eeprom_len
;
/* Usually 8kB, may be less */
int
eeprom_addr
;
/* 0x50, 0x52 etc */
uint8_t
*
eeprom
;
/* Full contents or leading part */
char
*
carrier_name
;
/* "SPEC" or similar, for special use */
void
*
carrier_data
;
/* "struct spec *" or equivalent */
__iomem
void
*
base
;
/* May be NULL (Etherbone) */
__iomem
void
*
fpga_base
;
/* May be NULL (Etherbone) */
__iomem
void
*
slot_base
;
/* Set by the driver */
struct
fmc_device
**
devarray
;
/* Allocated by the bus */
int
slot_id
;
/* Index in the slot array */
int
nr_slots
;
/* Number of slots in this carrier */
unsigned
long
memlen
;
/* Used for the char device */
struct
device
dev
;
/* For Linux use */
struct
device
*
hwdev
;
/* The underlying hardware device */
unsigned
long
sdbfs_entry
;
struct
sdb_array
*
sdb
;
uint32_t
device_id
;
/* Filled by the device */
char
*
mezzanine_name
;
/*
Built by fmc-core (allocated)
*/
char
*
mezzanine_name
;
/*
Defaults to ``fmc''
*/
void
*
mezzanine_data
;
};
#define to_fmc_device(x) container_of((x), struct fmc_device, dev)
...
...
@@ -182,14 +188,14 @@ static inline uint32_t fmc_readl(struct fmc_device *fmc, int offset)
{
if
(
unlikely
(
fmc
->
op
->
readl
))
return
fmc
->
op
->
readl
(
fmc
,
offset
);
return
readl
(
fmc
->
base
+
offset
);
return
readl
(
fmc
->
fpga_
base
+
offset
);
}
static
inline
void
fmc_writel
(
struct
fmc_device
*
fmc
,
uint32_t
val
,
int
off
)
{
if
(
unlikely
(
fmc
->
op
->
writel
))
fmc
->
op
->
writel
(
fmc
,
val
,
off
);
else
writel
(
val
,
fmc
->
base
+
off
);
writel
(
val
,
fmc
->
fpga_
base
+
off
);
}
/* pci-like naming */
...
...
@@ -209,6 +215,10 @@ extern void fmc_driver_unregister(struct fmc_driver *drv);
extern
int
fmc_device_register
(
struct
fmc_device
*
tdev
);
extern
void
fmc_device_unregister
(
struct
fmc_device
*
tdev
);
/* Two more for device sets, all driven by the same FPGA */
extern
int
fmc_device_register_n
(
struct
fmc_device
*
fmc
,
int
n
);
extern
void
fmc_device_unregister_n
(
struct
fmc_device
*
fmc
,
int
n
);
/* Internal cross-calls between files; not exported to otther modules */
extern
int
fmc_match
(
struct
device
*
dev
,
struct
device_driver
*
drv
);
extern
int
fmc_fill_id_info
(
struct
fmc_device
*
fmc
);
...
...
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