mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-05 07:26:48 +07:00
ac20ad14c3
Fix double words "is is" in Documentations. Signed-off-by: Masanari Iida <standby24x7@gmail.com> Acked-by: Rob Landley <rob@landley.net> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
312 lines
14 KiB
Plaintext
312 lines
14 KiB
Plaintext
FMC Device
|
|
**********
|
|
|
|
Within the Linux bus framework, the FMC device is created and
|
|
registered by the carrier driver. For example, the PCI driver for the
|
|
SPEC card fills a data structure for each SPEC that it drives, and
|
|
registers an associated FMC device for each card. The SVEC driver can
|
|
do exactly the same for the VME carrier (actually, it should do it
|
|
twice, because the SVEC carries two FMC mezzanines). Similarly, an
|
|
Etherbone driver will be able to register its own FMC devices, offering
|
|
communication primitives through frame exchange.
|
|
|
|
The contents of the EEPROM within the FMC are used for identification
|
|
purposes, i.e. for matching the device with its own driver. For this
|
|
reason the device structure includes a complete copy of the EEPROM
|
|
(actually, the carrier driver may choose whether or not to return it -
|
|
for example we most likely won't have the whole EEPROM available for
|
|
Etherbone devices.
|
|
|
|
The following listing shows the current structure defining a device.
|
|
Please note that all the machinery is in place but some details may
|
|
still change in the future. For this reason, there is a version field
|
|
at the beginning of the structure. As usual, the minor number will
|
|
change for compatible changes (like a new flag) and the major number
|
|
will increase when an incompatible change happens (for example, a
|
|
change in layout of some fmc data structures). Device writers should
|
|
just set it to the value FMC_VERSION, and be ready to get back -EINVAL
|
|
at registration time.
|
|
|
|
struct fmc_device {
|
|
unsigned long version;
|
|
unsigned long flags;
|
|
struct module *owner; /* char device must pin it */
|
|
struct fmc_fru_id id; /* for EEPROM-based match */
|
|
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 *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; /* Defaults to ``fmc'' */
|
|
void *mezzanine_data;
|
|
};
|
|
|
|
The meaning of most fields is summarized in the code comment above.
|
|
|
|
The following fields must be filled by the carrier driver before
|
|
registration:
|
|
|
|
* version: must be set to FMC_VERSION.
|
|
|
|
* owner: set to MODULE_OWNER.
|
|
|
|
* op: the operations to act on the device.
|
|
|
|
* irq: number for the mezzanine; may be zero.
|
|
|
|
* eeprom_len: length of the following array.
|
|
|
|
* eeprom_addr: 0x50 for first mezzanine and so on.
|
|
|
|
* eeprom: the full content of the I2C EEPROM.
|
|
|
|
* carrier_name.
|
|
|
|
* carrier_data: a unique pointer for the carrier.
|
|
|
|
* fpga_base: the I/O memory address (may be NULL).
|
|
|
|
* slot_id: the index of this slot (starting from zero).
|
|
|
|
* memlen: if fpga_base is valid, the length of I/O memory.
|
|
|
|
* hwdev: to be used in some dev_err() calls.
|
|
|
|
* device_id: a slot-specific unique integer number.
|
|
|
|
|
|
Please note that the carrier should read its own 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:
|
|
|
|
* flags.
|
|
|
|
* fru_id: filled by the bus, parsing the eeprom.
|
|
|
|
* slot_base: filled and used by the driver, if useful to it.
|
|
|
|
* devarray: an array og all mezzanines driven by a singe FPGA.
|
|
|
|
* nr_slots: set by the core at registration time.
|
|
|
|
* dev: used by Linux.
|
|
|
|
* sdb: FPGA contents, scanned according to driver's directions.
|
|
|
|
* sdbfs_entry: SDB entry point in EEPROM: autodetected.
|
|
|
|
* mezzanine_data: available for the driver.
|
|
|
|
* mezzanine_name: filled by fmc-bus during identification.
|
|
|
|
|
|
Note: mezzanine_data may be redundant, because Linux offers the drvdata
|
|
approach, so the field may be removed in later versions of this bus
|
|
implementation.
|
|
|
|
As I write this, she SPEC carrier is already completely functional in
|
|
the fmc-bus environment, and is a good reference to look at.
|
|
|
|
|
|
The API Offered by Carriers
|
|
===========================
|
|
|
|
The carrier provides a number of methods by means of the
|
|
`fmc_operations' structure, which currently is defined like this
|
|
(again, it is a moving target, please refer to the header rather than
|
|
this document):
|
|
|
|
struct fmc_operations {
|
|
uint32_t (*readl)(struct fmc_device *fmc, int offset);
|
|
void (*writel)(struct fmc_device *fmc, uint32_t value, int offset);
|
|
int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw);
|
|
int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv);
|
|
int (*irq_request)(struct fmc_device *fmc, irq_handler_t h,
|
|
char *name, int flags);
|
|
void (*irq_ack)(struct fmc_device *fmc);
|
|
int (*irq_free)(struct fmc_device *fmc);
|
|
int (*gpio_config)(struct fmc_device *fmc, struct fmc_gpio *gpio,
|
|
int ngpio);
|
|
int (*read_ee)(struct fmc_device *fmc, int pos, void *d, int l);
|
|
int (*write_ee)(struct fmc_device *fmc, int pos, const void *d, int l);
|
|
};
|
|
|
|
The individual methods perform the following tasks:
|
|
|
|
`readl'
|
|
`writel'
|
|
These functions access 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 fpga_base pointer, the driver may use direct
|
|
access through that pointer. For this reason the header offers the
|
|
inline functions fmc_readl and fmc_writel that access fpga_base if
|
|
the respective method is NULL. A driver that wants to be portable
|
|
and efficient should use fmc_readl and fmc_writel. For Etherbone,
|
|
or other non-local carriers, error-management is still to be
|
|
defined.
|
|
|
|
`validate'
|
|
Module parameters are used to manage different applications for
|
|
two or more boards of the same kind. Validation is based on the
|
|
busid module parameter, if provided, and returns the matching
|
|
index in the associated array. See *note Module Parameters:: in in
|
|
doubt. If no match is found, `-ENOENT' is returned; if the user
|
|
didn't pass `busid=', all devices will pass validation. The value
|
|
returned by the validate method can be used as index into other
|
|
parameters (for example, some drivers use the `lm32=' parameter in
|
|
this way). Such "generic parameters" are documented in *note
|
|
Module Parameters::, below. The validate method is used by
|
|
`fmc-trivial.ko', described in *note fmc-trivial::.
|
|
|
|
`reprogram'
|
|
The carrier enumerates FMC devices by loading a standard (or
|
|
golden) FPGA binary that allows EEPROM access. Each driver, then,
|
|
will need to reprogram the FPGA by calling this function. If the
|
|
name argument is NULL, the carrier should reprogram the golden
|
|
binary. If the gateware name has been overridden through module
|
|
parameters (in a carrier-specific way) the file loaded will match
|
|
the parameters. Per-device gateware names can be specified using
|
|
the `gateware=' parameter, see *note Module Parameters::. Note:
|
|
Clients should call rhe new helper, fmc_reprogram, which both
|
|
calls this method and parse the SDB tree of the FPGA.
|
|
|
|
`irq_request'
|
|
`irq_ack'
|
|
`irq_free'
|
|
Interrupt management is carrier-specific, so it is abstracted as
|
|
operations. The interrupt number is listed in the device
|
|
structure, and for the mezzanine driver the number is only
|
|
informative. The handler will receive the fmc pointer as dev_id;
|
|
the flags argument is passed to the Linux request_irq function,
|
|
but fmc-specific flags may be added in the future. You'll most
|
|
likely want to pass the `IRQF_SHARED' flag.
|
|
|
|
`gpio_config'
|
|
The method allows to configure a GPIO pin in the carrier, and read
|
|
its current value if it is configured as input. See *note The GPIO
|
|
Abstraction:: for details.
|
|
|
|
`read_ee'
|
|
`write_ee'
|
|
Read or write the EEPROM. The functions are expected to be only
|
|
called before reprogramming and the carrier should refuse them
|
|
with `ENODEV' after reprogramming. The offset is expected to be
|
|
within 8kB (the current size), but addresses up to 1MB are
|
|
reserved to fit bigger I2C devices in the future. Carriers may
|
|
offer access to other internal flash memories using these same
|
|
methods: for example the SPEC driver may define that its carrier
|
|
I2C memory is seen at offset 1M and the internal SPI flash is seen
|
|
at offset 16M. This multiplexing of several flash memories in the
|
|
same address space is carrier-specific and should only be used
|
|
by a driver that has verified the `carrier_name' field.
|
|
|
|
|
|
|
|
The GPIO Abstraction
|
|
====================
|
|
|
|
Support for GPIO pins in the fmc-bus environment is not very
|
|
straightforward and deserves special discussion.
|
|
|
|
While the general idea of a carrier-independent driver seems to fly,
|
|
configuration of specific signals within the carrier needs at least
|
|
some knowledge of the carrier itself. For this reason, the specific
|
|
driver can request to configure carrier-specific GPIO pins, numbered
|
|
from 0 to at most 4095. Configuration is performed by passing a
|
|
pointer to an array of struct fmc_gpio items, as well as the length of
|
|
the array. This is the data structure:
|
|
|
|
struct fmc_gpio {
|
|
char *carrier_name;
|
|
int gpio;
|
|
int _gpio; /* internal use by the carrier */
|
|
int mode; /* GPIOF_DIR_OUT etc, from <linux/gpio.h> */
|
|
int irqmode; /* IRQF_TRIGGER_LOW and so on */
|
|
};
|
|
|
|
By specifying a carrier_name for each pin, the driver may access
|
|
different pins in different carriers. The gpio_config method is
|
|
expected to return the number of pins successfully configured, ignoring
|
|
requests for other carriers. However, if no pin is configured (because
|
|
no structure at all refers to the current carrier_name), the operation
|
|
returns an error so the caller will know that it is running under a
|
|
yet-unsupported carrier.
|
|
|
|
So, for example, a driver that has been developed and tested on both
|
|
the SPEC and the SVEC may request configuration of two different GPIO
|
|
pins, and expect one such configuration to succeed - if none succeeds
|
|
it most likely means that the current carrier is a still-unknown one.
|
|
|
|
If, however, your GPIO pin has a specific known role, you can pass a
|
|
special number in the gpio field, using one of the following macros:
|
|
|
|
#define FMC_GPIO_RAW(x) (x) /* 4096 of them */
|
|
#define FMC_GPIO_IRQ(x) ((x) + 0x1000) /* 256 of them */
|
|
#define FMC_GPIO_LED(x) ((x) + 0x1100) /* 256 of them */
|
|
#define FMC_GPIO_KEY(x) ((x) + 0x1200) /* 256 of them */
|
|
#define FMC_GPIO_TP(x) ((x) + 0x1300) /* 256 of them */
|
|
#define FMC_GPIO_USER(x) ((x) + 0x1400) /* 256 of them */
|
|
|
|
Use of virtual GPIO numbers (anything but FMC_GPIO_RAW) is allowed
|
|
provided the carrier_name field in the data structure is left
|
|
unspecified (NULL). Each carrier is responsible for providing a mapping
|
|
between virtual and physical GPIO numbers. The carrier may then use the
|
|
_gpio field to cache the result of this mapping.
|
|
|
|
All carriers must map their I/O lines to the sets above starting from
|
|
zero. The SPEC, for example, maps interrupt pins 0 and 1, and test
|
|
points 0 through 3 (even if the test points on the PCB are called
|
|
5,6,7,8).
|
|
|
|
If, for example, a driver requires a free LED and a test point (for a
|
|
scope probe to be plugged at some point during development) it may ask
|
|
for FMC_GPIO_LED(0) and FMC_GPIO_TP(0). Each carrier will provide
|
|
suitable GPIO pins. Clearly, the person running the drivers will know
|
|
the order used by the specific carrier driver in assigning leds and
|
|
testpoints, so to make a carrier-dependent use of the diagnostic tools.
|
|
|
|
In theory, some form of autodetection should be possible: a driver like
|
|
the wr-nic (which uses IRQ(1) on the SPEC card) should configure
|
|
IRQ(0), make a test with software-generated interrupts and configure
|
|
IRQ(1) if the test fails. This probing step should be used because even
|
|
if the wr-nic gateware is known to use IRQ1 on the SPEC, the driver
|
|
should be carrier-independent and thus use IRQ(0) as a first bet -
|
|
actually, the knowledge that IRQ0 may fail is carrier-dependent
|
|
information, but using it doesn't make the driver unsuitable for other
|
|
carriers.
|
|
|
|
The return value of gpio_config is defined as follows:
|
|
|
|
* If no pin in the array can be used by the carrier, `-ENODEV'.
|
|
|
|
* If at least one virtual GPIO number cannot be mapped, `-ENOENT'.
|
|
|
|
* On success, 0 or positive. The value returned is the number of
|
|
high input bits (if no input is configured, the value for success
|
|
is 0).
|
|
|
|
While I admit the procedure is not completely straightforward, it
|
|
allows configuration, input and output with a single carrier operation.
|
|
Given the typical use case of FMC devices, GPIO operations are not
|
|
expected to ever by in hot paths, and GPIO access so fare has only been
|
|
used to configure the interrupt pin, mode and polarity. Especially
|
|
reading inputs is not expected to be common. If your device has GPIO
|
|
capabilities in the hot path, you should consider using the kernel's
|
|
GPIO mechanisms.
|