You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
5.7 KiB
123 lines
5.7 KiB
FMC Driver |
|
********** |
|
|
|
An FMC driver is concerned with the specific mezzanine and associated |
|
gateware. As such, it is expected to be independent of the carrier |
|
being used: it will perform I/O accesses only by means of |
|
carrier-provided functions. |
|
|
|
The matching between device and driver is based on the content of the |
|
EEPROM (as mandated by the FMC standard) or by the actual cores |
|
configured in the FPGA; the latter technique is used when the 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 |
|
FPGA registers, by means of the `fpga_base' field of the device |
|
structure. This may be needed for high-bandwidth peripherals like fast |
|
ADC cards. If the device module registered a remote device (for example |
|
by means of Etherbone), the `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 fmc_readl and fmc_writel instead, which will |
|
work in any case. |
|
|
|
In even more special cases, the driver may access carrier-specific |
|
functionality: the `carrier_name' string allows the driver to check |
|
which is the current carrier and make use of the `carrier_data' |
|
pointer. We chose to use carrier names rather than numeric identifiers |
|
for greater flexibility, but also to avoid a central registry within |
|
the `fmc.h' file - we hope other users will exploit our framework with |
|
their own carriers. An example use of carrier names is in GPIO setup |
|
(see *note The GPIO Abstraction::), although the name match is not |
|
expected to be performed by the driver. If you depend on specific |
|
carriers, please check the carrier name and fail gracefully if your |
|
driver finds it is running in a yet-unknown-to-it environment. |
|
|
|
|
|
ID Table |
|
======== |
|
|
|
Like most other Linux drivers, and FMC driver must list all the devices |
|
which it is able to drive. This is usually done by means of a device |
|
table, but in FMC we can match hardware based either on the contents of |
|
their EEPROM or on the actual FPGA cores that can be enumerated. |
|
Therefore, we have two tables of identifiers. |
|
|
|
Matching of FRU information depends on two names, the manufacturer (or |
|
vendor) and the device (see *note FMC Identification::); for |
|
flexibility during production (i.e. before writing to the EEPROM) the |
|
bus supports a catch-all driver that specifies NULL strings. For this |
|
reason, the table is specified as pointer-and-length, not a a |
|
null-terminated array - the entry with NULL names can be a valid entry. |
|
|
|
Matching on FPGA cores depends on two numeric fields: the 64-bit vendor |
|
number and the 32-bit device number. Support for matching based on |
|
class is not yet implemented. Each device is expected to be uniquely |
|
identified by an array of cores (it matches if all of the cores are |
|
instantiated), and for consistency the list is passed as |
|
pointer-and-length. Several similar devices can be driven by the same |
|
driver, and thus the driver specifies and array of such arrays. |
|
|
|
The complete set of involved data structures is thus the following: |
|
|
|
struct fmc_fru_id { char *manufacturer; char *product_name; }; |
|
struct fmc_sdb_one_id { uint64_t vendor; uint32_t device; }; |
|
struct fmc_sdb_id { struct fmc_sdb_one_id *cores; int cores_nr; }; |
|
|
|
struct fmc_device_id { |
|
struct fmc_fru_id *fru_id; int fru_id_nr; |
|
struct fmc_sdb_id *sdb_id; int sdb_id_nr; |
|
}; |
|
|
|
A better reference, with full explanation, is the <linux/fmc.h> header. |
|
|
|
|
|
Module Parameters |
|
================= |
|
|
|
Most of the FMC drivers need the same set of kernel parameters. This |
|
package includes support to implement common parameters by means of |
|
fields in the `fmc_driver' structure and simple macro definitions. |
|
|
|
The parameters are carrier-specific, in that they rely on the busid |
|
concept, that varies among carriers. For the SPEC, the identifier is a |
|
PCI bus and devfn number, 16 bits wide in total; drivers for other |
|
carriers will most likely offer something similar but not identical, |
|
and some code duplication is unavoidable. |
|
|
|
This is the list of parameters that are common to several modules to |
|
see how they are actually used, please look at spec-trivial.c. |
|
|
|
`busid=' |
|
This is an array of integers, listing carrier-specific |
|
identification numbers. For PIC, for example, `0x0400' represents |
|
bus 4, slot 0. If any such ID is specified, the driver will only |
|
accept to drive cards that appear in the list (even if the FMC ID |
|
matches). This is accomplished by the validate carrier method. |
|
|
|
`gateware=' |
|
The argument is an array of strings. If no busid= is specified, |
|
the first string of gateware= is used for all cards; otherwise the |
|
identifiers and gateware names are paired one by one, in the order |
|
specified. |
|
|
|
`show_sdb=' |
|
For modules supporting it, this parameter asks to show the SDB |
|
internal structure by means of kernel messages. It is disabled by |
|
default because those lines tend to hide more important messages, |
|
if you look at the system console while loading the drivers. |
|
Note: the parameter is being obsoleted, because fmc.ko itself now |
|
supports dump_sdb= that applies to every client driver. |
|
|
|
|
|
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. This has been tested with a SPEC carrier. |
|
|
|
insmod fmc-trivial.ko \ |
|
busid=0x0200,0x0400 \ |
|
gateware=fmc/fine-delay.bin,fmc/simple-dio.bin |
|
|
|
Please note that not all sub-modules support all of those parameters. |
|
You can use modinfo to check what is supported by each module.
|
|
|