Device driver
coyote_driver.h
Top-level file of the Coyote driver; entry and exit point.
Functions
- static int __init coyote_init (void)
Top-level function of the Coyote driver, called when the driver is inserted. This function simply calls the pci_init() function, which is responsible for setting up the FPGA, vFPGAs, memory mappings etc. (see the documentation)
NOTE: In the past, we used to support Enzian (ECI) but it has been deprecated as of 2024. If you would like to add support for Enzian, reach out to us on GitHub or check how the code use to look before, with the diff commit being: 4555431cf251100e2f16255f7f49e9f02ddfb96d
- static void __exit coyote_exit (void)
Reverse of the init function, called when the driver is removed Handles device clean-up, memory freeing etc. See the documentation in pci_dev
coyote_setup.h
Functions for initializing, setting up and freeing Coyote devices (vfpga_dev, reconfig_dev) and utility functions (set up sysfs, reading config etc.)
Functions
-
int read_shell_config(struct bus_driver_data *data)
Reads the synthesized shell configuration and populates fields of bus_driver_data The configuration was specifified during the hardware synthesis in CMakeLists.txt The method also prints the configuration to the kernel log; can be queryed with
dmesg
-
int allocate_card_resources(struct bus_driver_data *data)
Allocates and initializes metadata structs used for managing card memory, if enabled.
-
void free_card_resources(struct bus_driver_data *data)
Releases metadata structs used for managing card memory, if enabled; opposite of allocate_card_resources.
-
void init_spin_locks(struct bus_driver_data *data)
Initialize general (not used by individual vFPGAs) spin locks used in Coyote; used to protect shared resources and ensure safe access.
-
int create_sysfs_entry(struct bus_driver_data *data)
Initialize sysfs entry for Coyote; for more details see coyote_sysfs.h.
-
void remove_sysfs_entry(struct bus_driver_data *data)
Removes sysfs entry for Coyote; used oly when the driver is unloaded.
-
int alloc_vfpga_devices(struct bus_driver_data *data, dev_t device)
Allocates and registers all the char vFPGA devices (one for every region)
-
int setup_vfpga_devices(struct bus_driver_data *data)
Sets up the previously allocated vFPGA char devices (above); memory mapping registers, initializing work queues, mutexes etc.
-
void teardown_vfpga_devices(struct bus_driver_data *data)
Releases resources used by vFPGA char devices; destroys work queues etc., opposite of setup_vfpga_devices.
-
void free_vfpga_devices(struct bus_driver_data *data)
Frees the allocated vFPGA char devices and unregisters it from the OS; opposite of alloc_vfpga_devices.
-
int alloc_reconfig_device(struct bus_driver_data *data, dev_t device)
Allocates a char reconfig_device which is used to interact with the static layer for shell reconfiguration.
-
int setup_reconfig_device(struct bus_driver_data *data)
Sets up the previously allocated reconfig char device (above); initializing work queues, mutexes, hash tables etc.
-
void teardown_reconfig_device(struct bus_driver_data *data)
Releases resources used by the reconfig device; destroys work queues etc., opposite of setup_reconfig_device.
-
void free_reconfig_device(struct bus_driver_data *data)
Frees the allocated reconfig char device and unregisters it from the OS; opposite of alloc_reconfig_device.
coyote_sysfs.h
Coyote sysfs module.
sysfs is a virtual filesystem in Linux that exposes kernel objects and their attributes to the user-space It can be used for reading and writing various attributes of devices in the kernel-space The following methods retrieve or set attributes from memory-mapped FPGA registers The attributes can also be read and set from a standard Linux terminal, e.g., cat /sys/kernel/coyote_sysfs_0/<attribute>
In general, the methods in this file follow similar steps:
Parse a generic kernel object (kobj) into a Coyote-specific variable of type bus_driver_data
Ensure the parsed object is non-null, using BUG_ON(…)
Retrieve or set the target attribute
Functions
-
ssize_t cyt_attr_ip_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get FPGA IP address.
-
ssize_t cyt_attr_ip_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
Set FPGA IP address.
-
ssize_t cyt_attr_mac_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get FPGA MAC address.
-
ssize_t cyt_attr_mac_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
Set FPGA MAC address.
-
ssize_t cyt_attr_eost_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get PR end of start-up (EOS) time.
-
ssize_t cyt_attr_eost_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
Set PR end of start-up (EOS) time.
-
ssize_t cyt_attr_nstats_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get network stats on port QSFP0.
-
ssize_t cyt_attr_xstats_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get XDMA stats.
-
ssize_t cyt_attr_prstats_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get partial reconfiguration stats.
-
ssize_t cyt_attr_engines_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get engine stats.
-
ssize_t cyt_attr_cnfg_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Get Coyote FPGA configuration (N_REGIONS, EN_MEM, EN_STRM, EN_PR, EN_RDMA, TLB config etc.)
vfpga_gup.h
Header file for memory management of vFPGAs.
This file defines the functions for handling page faults, managing user pages, exporting necessary DMA Buffers for FPGA-GPU communication. NOTE: GUP stands for “Get User Pages”, which is a Linux kernel mechanism to pin user-space pages in memory and Coyote swaps the pages between host and card. NOTE: Previously (currently in LEGACY), there was an alternative memory management mechanism, using Linux’s Hetereogeneous Memory Management (HMM) framework.
The mapped user pages are stored in a hash_table, called user_buff_map Functions in this file implement high-level logic for managing Coyote memory And call functions in vfpga_hw.h that handle the low-level logic by writing to the memory-mapped registers in the FPGA Additionally, this file provides functions for peer-to-peer DMA Buffer management, enabling direct FPGA-GPU communication.
Important functions in this file include:
mmu_handler_gup; the top-level function, handles page faults issued by the FPGA
tlb_map_gup and tlb_unmap_gup; which maps/unmaps user pages to the TLB
offload_user_pages and sync_user_pages; handling the offloading and syncing of user pages between host and card
P2P DMA Buffer functions for managing DMA Buffers to FPGA-GPU communication
Functions
-
int mmu_handler_gup(struct vfpga_dev *device, uint64_t vaddr, uint64_t len, int32_t ctid, int32_t stream, pid_t hpid)
Top-level function; handles page faults issued by the FPGA.
- Parameters:
device – vFPGA char device
vaddr – Buffer virtual address corresponding to the page fault
len – Length, in bytes, of the page-faulting buffer
ctid – Coyote thread ID
stream – Access type: HOST (1) or CARD (0)
hpid – Host process ID
- Returns:
0 on success, negative error code on failure
-
struct user_pages *map_present(struct vfpga_dev *device, struct pf_aligned_desc *pf_desc)
Checks if a mapping is already present in the user buffer map.
- Parameters:
device – vFPGA char device
pf_desc – Aligned page fault descriptor; holds info about virtual address, length etc.
- Returns:
Pointer to the user_pages structure if mapping exists, NULL otherwise
-
void tlb_map_gup(struct vfpga_dev *device, struct pf_aligned_desc *pf_desc, struct user_pages *user_pg, pid_t hpid)
Creates a TLB mapping for the given user pages.
- Parameters:
device – vFPGA char device
pf_desc – Aligned page fault descriptor; holds info about virtual address, length etc.
user_pg – User pages structure
hpid – Host process ID
-
void tlb_unmap_gup(struct vfpga_dev *device, struct user_pages *user_pg, pid_t hpid)
Removes a TLB mapping for the given user pages.
- Parameters:
device – vFPGA char device
pf_desc – Aligned page fault descriptor; holds info about virtual address, length etc.
hpid – Host process ID
-
struct user_pages *tlb_get_user_pages(struct vfpga_dev *device, struct pf_aligned_desc *pf_desc, pid_t hpid, struct task_struct *curr_task, struct mm_struct *curr_mm)
Pins user pages and prepares them for TLB mapping.
A function that is first called when no mapping for a user page exists In this case, the function performs the following:
Allocates a new user_pages struct which holds informaton about page physical address, length etc.,
Pins the pages, to avoid them being swapped out
Flushes the cache to ensure data consistency between the FPGA and the CPU
Allocates the corresponding card buffer, if memory is enabled This function is immediately followed by a call to tlb_map_gup, which maps the user pages to the vFPGA’s TLB
- Parameters:
device – vFPGA char device
pf_desc – Aligned page fault descriptor
hpid – Host process ID
curr_task – Current task structure
curr_mm – Current memory management structure
- Returns:
Pointer to the user_pages structure on success, NULL on failure
-
int tlb_put_user_pages(struct vfpga_dev *device, uint64_t vaddr, int32_t ctid, pid_t hpid, int dirtied)
Releases user pages and removes their TLB mappings.
- Parameters:
device – vFPGA char device
vaddr – Starting virtual address
ctid – Coyote thread ID for which the pages were mapped
hpid – Host process ID for which the pages were mapped
dirtied – Indicates if the pages were modified
- Returns:
0 on success, negative error code on failure
-
int tlb_put_user_pages_ctid(struct vfpga_dev *device, int32_t ctid, pid_t hpid, int dirtied)
Releases all user pages for a given Coyote thread.
- Parameters:
device – vFPGA char device
ctid – Coyote thread ID for which the pages should be released
hpid – Host process ID associated with the Coyote thread
dirtied – Indicates if the pages were modified
- Returns:
0 on success, negative error code on failure
-
void migrate_to_card(struct vfpga_dev *device, struct user_pages *user_pg)
Helper function, migrates user pages to card memory.
- Parameters:
device – vFPGA char device
user_pg – User pages to be migrated
-
void migrate_to_host(struct vfpga_dev *device, struct user_pages *user_pg)
Helper function, migrates user pages back to the host memory.
- Parameters:
device – vFPGA char device
user_pg – User pages to be migrated
-
int offload_user_pages(struct vfpga_dev *device, uint64_t vaddr, uint32_t len, int32_t ctid)
Trigger off-load operation; moving pages from host to card & updating mappings.
- Parameters:
device – vFPGA char device
vaddr – Starting virtual address of the buffer to be offloaded
len – Length, in bytes, of the buffer to be offloaded
ctid – Coyote thread ID
- Returns:
0 on success, negative error code on failure
-
int sync_user_pages(struct vfpga_dev *device, uint64_t vaddr, uint32_t len, int32_t ctid)
Trigger sync operation; moving pages from card to host & updating mappings.
- Parameters:
device – vFPGA char device
vaddr – Starting virtual address of the buffer to be synced
len – Length, in bytes, of the buffer to be synced
ctid – Coyote thread ID
- Returns:
0 on success, negative error code on failure
-
void p2p_move_notify(struct dma_buf_attachment *attach)
Callback for handling page movement notifications in peer-to-peer DMA.
To manage page movements in GPU memory, this routines deletes TLB entries and retrieves new entries It is passed as a parameter to the dma_buf_attach_ops struct, which is used when attaching the DMA Buffer
- Parameters:
attach – DMA buffer attachment structure
-
int p2p_attach_dma_buf(struct vfpga_dev *device, int buf_fd, uint64_t vaddr, int32_t ctid)
Attaches a DMA buffer to the vFPGA.
In general, this functions implements similary logic as tlb_get_user_pages, but for DMA Buffers Functionality includes:
Allocating a new user_pages struct which holds informaton about page physical address, length etc.,
Attaches the DMA Buffer to the vFPGA char device, allowing the vFPGA to access the buffer
Maps the DMA Buffer to the FPGA’s address spae, by providing a scatter-gather list represnting the physical memory of the buffer
Allocate corresponding card buffer, if memory is enabled
Maps the physical to virtual translations to the vFPGA’s TLB using tlb_map_gup
- Parameters:
device – vFPGA char device
buf_fd – File descriptor of the DMA buffer
vaddr – Virtual address to map the buffer
ctid – Coyote thread ID
- Returns:
0 on success, negative error code on failure
-
int p2p_detach_dma_buf(struct vfpga_dev *device, uint64_t vaddr, int32_t ctid, int dirtied)
Detaches a DMA buffer from the vFPGA device.
In general, this functions implements similary logic as tlb_put_user_pages, but for DMA Buffers It is called at the end of the Coyote thread’s execution, when the buffer is no longer needed Functionality includes (which is largely opposite to p2p_attach_dma_buf):
Removing the TLB entries using tlb_unmap_gup
Freeing card memory, if memory is enabled
Unmapping the DMA Buffer from the vFPGA’s address space
Detaching the vFPGA device from the DMA Buffer
- Parameters:
device – vFPGA char device
vaddr – Virtual address of the buffer
ctid – Coyote thread ID
dirtied – Indicates if the buffer was modified
- Returns:
0 on success, negative error code on failure
vfpga_hw.h
vFPGA hardware functions
Functions in this file are primarily used for low-level hardware operations in the vFPGA Typically, this includes writing to or reading from hardware registers, which are memory-mapped during driver loading The registers typically start an operation in hardware or contain some control flow data (virtual address, length etc.)
Functions
-
uint32_t read_irq_type(struct vfpga_dev *device)
Parse interrupt type.
- Parameters:
device – vFPGA char device
- Returns:
type of interrupt (IRQ_DMA_OFFL, IRQ_DMA_SYNC, IRQ_INVLDT, IRQ_PFAULT, IRQ_NOTIFY)
-
void read_irq_notify(struct vfpga_dev *device, struct vfpga_irq_notify *irq_not)
Parse user notification IRQ.
- Parameters:
device – vFPGA char device
irq_not – notification struct, to be set (updated) by this function
-
void read_irq_pfault(struct vfpga_dev *device, struct vfpga_irq_pfault *irq_pf)
Parse page fault IRQ.
- Parameters:
device – vFPGA char device
irq_pf – page fault struct, to be set (updated) by this function
-
void drop_irq_pfault(struct vfpga_dev *device, bool write, int32_t ctid)
Drops the page fault, because it went wrong somewhere.
- Parameters:
device – vFPGA char device
write – write operation (true) or read operation (false)
ctid – Coyote thread ID
-
void clear_irq(struct vfpga_dev *device)
Resets the IRQ registers in hardware.
- Parameters:
device – vFPGA char device
-
void restart_mmu(struct vfpga_dev *device, bool write, int32_t ctid)
Restarts the MMU, by signaling a page fault has correctly been handled.
- Parameters:
device – vFPGA char device
write – write operation (true) or read operation (false)
ctid – Coyote thread ID
-
void invalidate_tlb_entry(struct vfpga_dev *device, uint64_t vaddr, uint32_t n_pages, int32_t hpid, bool last)
Invalidate a TLB entry.
- Parameters:
device – vFPGA char device
vaddr – starting virtual address of the buffer to be invalidated
n_pages – number of consecutive pages to be invalidated
hpid – host process ID
last – is this the last page of the buffer to be invalidated (equivalent to a tlast in an AXI stream)
-
void change_tlb_lock(struct vfpga_dev *device)
Locks or unlocks the TLB, potentially prevent new entries (if locked)
- Parameters:
device – vFPGA char device
-
void create_tlb_mapping(struct vfpga_dev *device, struct tlb_metadata *tlb_meta, uint64_t vaddr, uint64_t physical_address, int32_t host, int32_t ctid, pid_t hpid)
Create a TLB mapping.
- Parameters:
device – vFPGA char device
tlb_meta – helper struct, containing TLB information (page size & shift, key size & shift etc.)
vaddr – buffer virtual address
physical_address – buffer physical address
host – does the buffer reside in host memory (1) or in card memory (0)
ctid – Coyote thread ID
hpid – Host process ID
-
void create_tlb_unmapping(struct vfpga_dev *device, struct tlb_metadata *tlb_meta, uint64_t vaddr, pid_t hpid)
Unmap TLB entry.
- Parameters:
device – vFPGA char device
tlb_meta – helper struct, containing TLB information (page size & shift, key size & shift etc.)
vaddr – buffer virtual address
hpid – Host process ID
-
void trigger_dma_offload(struct vfpga_dev *device, uint64_t *host_address, uint64_t *card_address, uint32_t n_pages, bool huge)
Triggers DMA off-load from host memory to card memory (asynchronous)
- Parameters:
device – vFPGA char device
host_address – - virtual address of the buffer on the host to be off-loaded
card_address – - target virtual address on the card
n_pages – - number of pages in the buffer to be off-loaded
huge – - whether the buffer is using hugepages or regular pages
-
void trigger_dma_sync(struct vfpga_dev *device, uint64_t *host_address, uint64_t *card_address, uint32_t n_pages, bool huge)
Triggers DMA sync from card memory to host memory (asynchronous)
- Parameters:
device – vFPGA char device
host_address – - target virtual address of the buffer on the host
card_address – - virtual address of the buffer on the card
n_pages – - number of pages in the buffer to be synced
huge – - whether the buffer is using hugepages or regular pages
-
int alloc_card_memory(struct vfpga_dev *device, uint64_t *card_physical_address, uint32_t n_pages, bool huge)
Allocates memory on the card’s HBM or DDR memory and updates the card_physical_address parameter with the allocated addresses.
- Parameters:
device – vFPGA char device
card_physical_address – initially null/empty, set by the function to reflect the physical address of the allocated pages
n_pages – number of pages to be allocated
huge – whether the memory is using hugepages or regular pages
- Returns:
whether the allocation was successful; can fail if there is insufficient space on the card
-
void free_card_memory(struct vfpga_dev *device, uint64_t *card_physical_address, uint32_t n_pages, bool huge)
Release memory on the card; opposite of the above alloc_card_memory function.
- Parameters:
device – vFPGA char device
card_physical_address – list of pages allocated on the card’s memory and their corresponding physical addresses
n_pages – number of pages to be freed
huge – whether the memory to be freed is using hugepages or regular pages
vfpga_isr.h
vFPGA interrupts (page faults, invalidations, user interrupts etc.)
Functions
-
irqreturn_t vfpga_isr(int irq, void *d)
Top-level vFPGA interrupt routine; registered during set-up in msix_irq_setup(…)
Catches interrupts issued by the vFPGA (sent via XDMA and PCIe) and calls the appropriate callback method Interrupts, in the order of importance are:
Completed DMA offloads/syncs
Completed TLB invalidation
Page fault
User interrupts (notification)
For more details, refer to: Chapter 3.1.3.5 Interrupts in Abstractions for Modern Heterogeneous Systems (2024), Dario Korlija
- Parameters:
irq – Interrupt type
d – Generic pointer to a Linux device; internally parsed into a vfpga_dev pointer
-
void vfpga_notify_handler(struct work_struct *work)
Handles user interupts (notifications)
-
void vfpga_pfault_handler(struct work_struct *work)
Handles vFPGA page faults, by invalidating and updating TLB; migrating data where required.
vfpga_ops.h
Standard device operations for the vfpga_dev char device: open, release, ioctl and memory map (mmap)
vfpga_uisr.h
vFPGA user interrupts (notifications)
Methods to register user interrupt (notification) callbacks, as requested by the user In Coyote, user interrupts (notifications) are linked to a Coyote thread, through its ID (ctid) Therefore, there can be multiple interrupt callbacks for one vFPGA, since it’s possible to have more than one Coyote thread per vFPGA For more details, see Example 3: Multi-threading and Example 4: User interrupts
To handle interrupts, Coyote uses eventfd, a Linux kernel mechanism for event signalling eventfd can be used to communicate events between the kernel- and the user-space, or between processes In Coyote, an eventfd is created from the user-space and registered by the driver using the method vfpga_register_eventfd Then, when an interrupt from the FPGA is picked up by the driver (see vfpga_isr.c), the driver writes to the appropariate eventfd The user-space software polls on the same eventfd, and, when a change is detected, executes the appropriate callback (see sw/bThread.cpp)
Functions
-
int vfpga_register_eventfd(struct vfpga_dev *device, int ctid, int eventfd)
Registers an eventfd for a given Coyote thread and vFPGA device.
- Parameters:
device – vfpga_dev for which the eventfd should be registered
ctid – Coyote thread ID (obtained from user-space)
eventfd – eventfd file descriptor, as created in the user-space (see sw/bThread.cpp)
- Returns:
whether eventfd was successfully registered
-
void vfpga_unregister_eventfd(struct vfpga_dev *device, int ctid)
Unregisters an eventfd for a given Coyote thread and vFPGA device.
- Parameters:
device – vfpga_dev for which the eventfd should be released
ctid – Coyote thread ID of the eventfd which should be released
reconfig_hw.h
Low-level hardware functionality to trigger run-time reconfiguration of the FPGA.
Functions
-
int reconfigure_start(struct reconfig_dev *device, uint64_t vaddr, uint64_t len, pid_t pid, uint32_t crid)
Triggers the reconfiguration process.
- Parameters:
device – reconfig_device to be reconfigured (corresponding to the actual physical FPGA we want to reconfigure)
vaddr – bitstream buffer virtual address; obtained from alloc_buffer and mmap
pid – host process ID
crid – configuration ID
- Returns:
reconfiguration started successfuly or not
reconfig_isr.h
Reconfiguration interrupt management; picking up interrupts when reconfiguration is complete.
Functions
-
irqreturn_t reconfig_isr(int irq, void *dev)
Handles incoming interrupts related to reconfiguration.
A reconfiguration interrupt issued by the FPGA corresponds to reconfiguration being completed successfuly Once picked up by this function, it sets the wait_rcnfg variable to SET, which is polled on during IOCTL_RECONFIGURE_(SHELL|APP) Finally, it clears the memory-mapped interrupt register in the FPGA
- Parameters:
irq – interrupt value
dev – pointer to the reconfiguration device being reconfigured
- Returns:
IRQ_HANDLED, indicating interrupt has been acknowledged
reconfig_mem.h
Memory management for reconfiguration: allocating and releasing memory to hold partial bitstreams.
Functions
-
int alloc_reconfig_buffer(struct reconfig_dev *device, unsigned long n_pages, pid_t pid, uint32_t crid)
Allocates host-side, kernel-space reconfiguration buffers.
In order for partial bitstreams to be loaded onto the FPGA, they need to be written to the ICAP from the driver via PCIe and the XDMA core This function allocates a buffer of sufficient size to hold a partial bitstream for reconfiguration Following this function, the buffer is mapped to the user-space using an mmap call (reconfig_ops.h) Finally, the partial bitstream can then be loaded into this buffer and used to trigger reconfiguration
- Parameters:
device – reconfig_device for which the bitstream buffer should be allocated
n_pages – number of hugepages required to hold the bitsream; calculated in user-space
pid – host process ID
crid – configuration ID (uniquely identifies the shell bitstream to be loaded)
- Returns:
whether target memory allocation completed successfully
-
int free_reconfig_buffer(struct reconfig_dev *device, uint64_t vaddr, pid_t pid, uint32_t crid)
De-allocates host-side, kernel-space reconfiguration buffer.
Performs the opposite of the function above; to be used when reconfiguration is complete
- Parameters:
device – reconfig_device for which the bitstream buffer should be allocated
vaddr – buffer virtual address
pid – host process ID
crid – configuration ID
- Returns:
always 0; check reconfig_mem.c for explanation
reconfig_ops.h
Standard device operations for the reconfig_dev char device: open, release, ioctl and memory map (mmap)
pci_util.h
Coyote PCI utility functions.
Functions
-
inline uint32_t build_u32(uint32_t hi, uint32_t lo)
Utility functions, concatenates two 16-bit values into a single 32-bit value.
-
void pci_enable_capability(struct pci_dev *pdev, int cmd)
Enables a specific PCIe capability for the device.
- Parameters:
pdev – Pointer to the PCI device structure
capability – Capability to enable
-
bool msix_capable(struct pci_dev *pdev)
Checks if the PCI device supports MSI-X.
- Parameters:
pdev – Pointer to the PCI device structure.
- Returns:
true
if MSI-X is supported,false
otherwise.
pci_xdma.h
Contains functions for loading and setting up the Coyote driver on PCI platforms with the XDMA core.
Functions
-
void assign_device_id(struct bus_driver_data *data)
Assign a unique ID to each Coyote-enabled FPGA card and set the unique device name.
-
void vfpga_interrupts_enable(struct bus_driver_data *data)
Enables interrupts issued from vFPGAs.
Interrupts issued through the XDMA core must be enabled By writing to the IRQ Block User Interrupt Enable Mask W1S (0x08) register W1S means “Write 1 to Set”, which means that bits set to 1 in the mask Will enable the corresponding interrupts For more information, refer to the XDMA specification [PG195 (v4.1)] In particular, page 59 onwards, Table 78 and Table 81 for this function
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
-
void vfpga_interrupts_disable(struct bus_driver_data *data)
Disables interrupts issued from vFPGAs.
Interrupts issued through the XDMA core can be disabled (for e.g., when removing the driver) To do so, it’s necessary to write to the IRQ Block User Interrupt Enable Mask W1C (0x12) register W1C means “Write 1 to Clear”, which means that bits set to 1 in the mask Will disable the corresponding interrupts For more information, refer to the XDMA specification [PG195 (v4.1)] In particular, page 59 onwards, Table 78 and Table 82 for this function
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
-
void reconfig_interrupt_enable(struct bus_driver_data *data)
Enables interrupts issued for reconfiguration.
Interrupts issued through the XDMA core must be enabled By writing to the IRQ Block User Interrupt Enable Mask W1S (0x08) register The method is the same as for vFPGAs (above), but the mask is different More informaction in the XDMA specification [PG195 (v4.1)], p59 onwards, Tables 78 and 81
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
-
void reconfig_interrupt_disable(struct bus_driver_data *data)
Disables interrupts used for reconfiguration.
Similar implemenation as in vfpga_interrupts_disable, with a different For more information, see above functions and the XDMA specification, p59 onwards, Tables 78 and 82
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
-
uint32_t read_interrupts(struct bus_driver_data *data)
Reads the interrupts registers from the XDMA core.
Util function which can be used for debugging but also to flush previous register values For more details on the registers values, refer to the XDMA specification [PG195 (v4.1)], Tables 78, 86, 87
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
- Returns:
32-bit value containing the interrupts requests; low 16 are user, top 16 are channel (unused in Coyote)
-
uint32_t build_vector_reg(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
Utility function, constructs a 32-bit MSI-X vector register value.
This function packs four 5-bit fields (a, b, c, d) into a single 32-bit value. Each field represents an MSI-X table entry index 5 bit-values are used, per the XDMA specification [PG195 (v4.1)], Table 90 onwards
- Parameters:
a – The first 5-bit field (bits 0–4)
b – The second 5-bit field (bits 8–12)
c – The third 5-bit field (bits 16–20)
d – The fourth 5-bit field (bits 24–28)
- Returns:
A 32-bit value representing the packed MSI-X vector register
-
void write_msix_vectors(struct bus_driver_data *data)
Writes MSI-X vectors to the XDMA configuration registers; per Table 90 in the XDMA specification.
MSI-X vectors are required to uniquely identify an interrupt source and therefore call the correct ISR handler function. In Coyote, we write one vector for each vFPGA device and one for the reconfiguration process In total, there are at most 15 (vFPGA) interrupts and 1 (reconfiguration) interrupt, hence 16 vectors
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
-
int irq_setup(struct bus_driver_data *data, struct pci_dev *pdev, bool enable_reconfig_irq)
Sets up Coyote IRQs for vfpga and reconfig devices.
This function initializes the MSI-X interrupt vectors for the device and associates them with the appropriate interrupt handler functions (vfpga_isr, reconfig_isr).
Note
enable_reconfig_irq is used to determine whether to set up the reconfiguration interrupt. Additionally, it is used to indicate the “first” set-up of the Coyote driver, when the bitstram is loaded using the Vivado Hardware Manager. When this happens, the MSI-X vectors need to be written to the XDMA configuration registers using the write_msix_vectors function. However, this function is also called after shell_pci_init, which is used when dynamically reconfiguring the shell Then, there is no need to write the MSI-X vectors again, as they are already set up (the XDMA core stays online during shell reconfiguration). However, the IRQ vectors need to be re-initialized for the vFPGA devices (but not for the reconfiguration device).
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
pdev – Pointer to the PCI device structure associated with the Coyote device.
enable_reconfig_irq – Boolean flag to enable reconfiguration interrupts.
- Returns:
0 on success, negative error code on failure.
-
void irq_teardown(struct bus_driver_data *data, bool enable_reconfig_irq)
Removes previously set-up IRQs (opposite of irq_setup)
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
enable_reconfig_irq – Boolean flag to disable reconfiguration interrupts; same purpose as in irq_setup.
-
int pci_check_msix(struct bus_driver_data *data, struct pci_dev *pdev)
Checks if MSI-X is supported and enabled for the PCI device.
This function verifies the presence of MSI-X capability in the PCI device and allocates the required number of MSI-X vectors, which are later used in irq_setup.
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
pdev – Pointer to the PCI device structure associated with the Coyote device.
- Returns:
0 on success, negative error code on failure.
-
uint32_t get_engine_channel_id(struct xdma_engine_regs *regs)
Returns the channel ID of the engine; see Tables 41 & 60 in the XDMA specification [PG195 (v4.1)].
-
uint32_t get_engine_id(struct xdma_engine_regs *regs)
Returns the enginer ID; see Tables 41 & 60 in the XDMA specification [PG195 (v4.1)].
-
void read_engine_alignments(struct xdma_engine *engine)
Reads from the XDMA aligment registers (address bits and alignment, length granularity) and sets the values in the engine struct.
-
struct xdma_engine *engine_create(struct bus_driver_data *data, int offs, int c2h, int channel)
Creates a C2H or H2C engine.
Allocates and initializes an XDMA engine structure for either C2H (Card-to-Host) or H2C (Host-to-Card) data transfer. It sets up the engine metadata, including its channel and direction. Additionally, it resets the engine by writing to its control registers.
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
offset – Offset of the engine configuration register; obtained from the XDMA specification [PG195 (v4.1)], Table 38
c2h – Direction of the engine (1 for C2H, 0 for H2C)
channel – Channel number of the engine
- Returns:
Pointer to the created engine structure, or NULL on failure
-
int probe_for_engine(struct bus_driver_data *data, int c2h, int channel)
Probes a single C2H or H2C engine.
This function initializes an XDMA engine for a specific channel and direction. Mostly a wrapper around engine_create, but also performs some sanity checks.
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
c2h – Direction of the engine (1 for C2H, 0 for H2C)
channel – Channel number of the engine
- Returns:
0 on success, negative error code on failure
-
int probe_engines(struct bus_driver_data *data)
Probes all C2H and H2C engines.
This function iterates through all available channels and initializes XDMA engines for both C2H and H2C directions.
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
- Returns:
0 on success, negative error code on failure
-
void engine_destroy(struct bus_driver_data *data, struct xdma_engine *engine)
Removes a single XDMA engine.
Deallocates resources associated with a specific XDMA engine and resets control registers in hardware.
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
engine – Pointer to the XDMA engine structure to be removed
-
void remove_engines(struct bus_driver_data *data)
Remove all XDMA engines.
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
-
int map_single_bar(struct bus_driver_data *data, struct pci_dev *pdev, int idx, int curr_idx)
Maps a single BAR (Base Address Register) of the PCI device.
This function maps a specific BAR to the driver’s address space, using the
pci_iomap
function. Additionally, it includes sanity checks for the BAR type and size.Note
We need to distinguish between idx and curr_idx, since in Coyote curr_idx goes can be 0, 1, 2 However, idx is the index of the BAR in the PCI device structure, which can be between 0 and 6. If the XDMA core is configure to have 64-bit addresses, then each BAR takes two slots, as explained in Table 3 of the XDMA specification [PG195 (v4.1)].
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information.
pdev – Pointer to the PCI device structure.
idx – Index of the BAR to be mapped.
curr_idx – Index in the driver’s BAR array where the mapped BAR will be stored. This is incremented for each successfully mapped BAR and ensures that the mapped BARs are stored sequentially in the driver’s data structure.
- Returns:
0 on success, negative error code on failure.
-
int map_bars(struct bus_driver_data *data, struct pci_dev *pdev)
Maps all BARs for the Coyote driver.
This function iterates through all available BARs of the PCI device and maps them into the driver’s address space using
map_single_bar
.- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
pdev – Pointer to the PCI device structure
- Returns:
0 on success, negative error code on failure.
-
void unmap_bars(struct bus_driver_data *data, struct pci_dev *pdev)
Unmaps all previously mapped BARs of the PCI device.
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
pdev – Pointer to the PCI device structure.
-
int shell_pci_init(struct bus_driver_data *data)
(Re-)Initializes the Coyote shell when running on PCI platforms
This function implements a subset of the pci_probe functionality and it should be used to re-initialize the Coyote shell after partial reconfiguration It is called from reconfig_ops.c during the reconfiguration process
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
- Returns:
0 on success, negative error code on failure.
-
void shell_pci_remove(struct bus_driver_data *data)
Clears the state of the Coyote shell when running on PCI platforms.
This function releases the resources and resets the hardware components associated with the shell layer. Only called when the shell is removed through reconfiguration (from reconfig_ops.c).
- Parameters:
data – Pointer to the bus driver data structure, containing Coyote device information
-
int pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Top-level PCI initialization function for the Coyote driver.
This function is called during the PCI device enumeration process to initialize the Coyote driver for the detected PCI device. It sets up the necessary resources, mapping the device’s BARs, initializing the XDMA engines, setting up char devices etc.
-
void pci_remove(struct pci_dev *pdev)
Top-level PCI device removal function for the Coyote driver.
This function is called during the PCI device removal process to clean up the resources and de-initialize the Coyote driver
-
int pci_init(void)
Top-level entry function, called by coyote_init and simply a wrapper around pci_probe.
-
void pci_exit(void)
Top-level exit function, called by coyote_exit and simply a wrapper around pci_remove.