/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2024 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ ================================================================== */ #ifndef __PCIE_DMA_H__ #define __PCIE_DMA_H__ #include #include #include #include #include #include #include #include #include #include #include "pcie_dma_regs.h" #ifndef MAX_PCI_BARS #define MAX_PCI_BARS 7 #endif #define SUCCESS 0 #define ERR -1 #define DMA_CHANNEL_NUM 0 #define FALSE 0 #define TRUE 1 #define WAITING -2 #define OK 0 /* Change these defines to increase number of boards supported by the driver */ #define NUM_BARS MAX_PCI_BARS #define NUM_BOARDS 4 /* 4 PCIe boards per system is a lot of PCIe slots and eval boards to have on hand */ #define MAX_BOARDS (NUM_BOARDS) #define MINORS_PER_BOARD 4 /* 3 minor number per discrete device */ #define MAX_MINORS (MAX_BOARDS * MINORS_PER_BOARD) #define LSC_BOARD 1 #define DMA_DEMO 1 // NOTE: these assume the first minor number is always 0, which is probably safe ;-) #define DMA_MINOR_TO_BOARD(a) (a / MINORS_PER_BOARD) #define DMA_MINOR_TO_FUNCTION(a) (a & (MINORS_PER_BOARD - 1)) #define STAT_CMD_REG 1 #define CAP_PTR_REG 13 #define PCI_CMD_REG 0x4 #define BME_MSE_ENABLE 0x6 #define VENDOR_ID 0x1204 #define DEVICE_ID 0x9C3e //#define DEVICE_ID 0x9C25 //#define VENDOR_ID 0x19AA //#define DEVICE_ID 0xE004 #define CRIT_ERR 0x1 #define NUM_DMA_CHANNELS 1 #define MAX_DRIVER_NAME_LEN 128 #define MAX_DRIVER_VERSION_LEN 128 #define MAX_NUM_MSI_VEC 1 #define MAX_NUM_DESCRIPTORS 32 #define DESC_MODE_SINGLE 0 #define DESC_MODE_CIRCULAR 1 #define INTX_ENABLE 0x1 #define MSI_ENABLE 0x2 #define MSI_DISABLE 0 #define DMA_IS_DONE 1 #define DMA_NOT_DONE 0 #define CONT_DESC_MAX 64 #define CONT_DESC_64 0 /*Value to be programmed if CONT DESC is 64*/ #define MSI #define USE_PROC /** * @brief PCIE DMA IOCTL Definitions * * This section defines various IOCTL commands used for PCIE DMA communication. * Each command corresponds to a specific operation or configuration. * * @note The actual implementation details are not provided here. */ #define PCIEDMA_MAGIC 'Z' #define IOCTL_PCIEDMA_F2H_DESC_GEN _IOW(PCIEDMA_MAGIC, 0, struct dma_f2h_ubuf_ioctl_arg) #define IOCTL_PCIEDMA_H2F_DESC_GEN _IOW(PCIEDMA_MAGIC, 1, struct dma_h2f_ubuf_ioctl_arg) #define IOCTL_PCIEDMA_F2H_START _IO(PCIEDMA_MAGIC, 2) #define IOCTL_PCIEDMA_H2F_START _IO(PCIEDMA_MAGIC, 3) #define IOCTL_PCIEDMA_F2H_STOP _IO(PCIEDMA_MAGIC, 4) #define IOCTL_PCIEDMA_H2F_STOP _IO(PCIEDMA_MAGIC, 5) #define IOCTL_PCIEDMA_GET_VERSION_INFO _IOR(PCIEDMA_MAGIC, 6, DriverVerStr_t) #define IOCTL_PCIEDMA_READ_8BIT _IOR(PCIEDMA_MAGIC, 7, int) #define IOCTL_PCIEDMA_READ_16BIT _IOR(PCIEDMA_MAGIC, 8, int) #define IOCTL_PCIEDMA_READ_32BIT _IOR(PCIEDMA_MAGIC, 9, int) #define IOCTL_PCIEDMA_GET_RESOURCES _IOR(PCIEDMA_MAGIC, 10, PCIResourceInfo_t) #define IOCTL_PCIEDMA_WRITE_16BIT _IOW(PCIEDMA_MAGIC, 11, int) #define IOCTL_PCIEDMA_WRITE_32BIT _IOW(PCIEDMA_MAGIC, 12, int) #define IOCTL_PCIEDMA_WRITE_8BIT _IOW(PCIEDMA_MAGIC, 13, int) #define IOCTL_PCIEDMA_CFG_REG_READ _IOR(PCIEDMA_MAGIC, 14, int) #define IOCTL_PCIEDMA_CFG_REG_WRITE _IOWR(PCIEDMA_MAGIC, 15, int) #define IOCTL_PCIEDMA_F2H_CHECK_DONE _IOWR(PCIEDMA_MAGIC, 16, int) #define IOCTL_PCIEDMA_H2F_CHECK_DONE _IOWR(PCIEDMA_MAGIC, 17, int) #define IOCTL_PCIEDMA_TOTAL_F2H_ENTRIES_CHECK _IOR(PCIEDMA_MAGIC, 18, int) #define IOCTL_PCIEDMA_TOTAL_H2H_ENTRIES_CHECK _IOR(PCIEDMA_MAGIC, 19, int) /** * @brief Structure for DMA F2H user buffer IOCTL arguments. * * This structure is used to pass arguments for DMA F2H (FPGA to Host) * user buffer IOCTL operations. * * @param addr Address of the user buffer. * @param len Length of each buffer. All buffers must have the same size. * @param desc_cnt Descriptor count. * @param descriptor_mode Descriptor mode. */ typedef struct dma_f2h_ubuf_ioctl_arg { void **addr; size_t len; int desc_cnt; uint8_t descriptor_mode; } dma_f2h_ubuf_ioctl_t; /** * @brief Structure for DMA H2F user buffer IOCTL arguments. * * This structure is used to pass arguments for DMA H2F (Host to FPGA) * user buffer IOCTL operations. * * @param addr Address of the user buffer. * @param len Length of each buffer. All buffers must have the same size. * @param desc_cnt Descriptor count. * @param descriptor_mode Descriptor mode. */ typedef struct dma_h2f_ubuf_ioctl_arg { void **addr; size_t len; int desc_cnt; uint8_t descriptor_mode; } dma_h2f_ubuf_ioctl_t; /** * @brief Structure for DMA read/write IOCTL arguments. * * This structure is used to pass arguments for DMA read/write * IOCTL operations. * * @param reg Register address. * @param value Value to be written or read. */ typedef struct dma_rw_ioctl_arg { uint32_t reg; uint32_t value; } dma_rw_ioctl_t; /** * @brief Type definition for driver version string. * * This type is used to define a string for the driver version. */ typedef char DriverVerStr_t[MAX_DRIVER_VERSION_LEN]; /** * @brief Structure for PCI BAR information. * * This structure contains information about the characteristics of a * device BAR (Base Address Register) mapped into the driver's memory space. * It is used by the driver to access device memory locations within this BAR. * * @param nBAR BAR number (0-5). * @param physStartAddr Physical start address of the BAR. * @param size Size of the memory window in bytes. * @param memMapped True if the driver has mapped this bus address into user space. * @param flags Memory type flags (Windows specifics). * @param type Memory or IO type (see Windows specifics). */ typedef struct { unsigned long nBAR; unsigned long physStartAddr; unsigned long size; bool memMapped; uint16_t flags; uint8_t type; } PCI_BAR_t; /** * @brief Structure to hold PCI resource information. * * This structure contains information about the PCI resources assigned to a device, * including the number of active BARs, details of each BAR, raw PCI configuration * register values, and interrupt information. * * @param numBARs Number of active BARs the device has been assigned. * @param BAR Structure containing information for all possible BARs. * @param PCICfgReg Raw PCI configuration register values. * @param hasInterrupt True if the device asked for and is assigned an interrupt. * @param intrVector The interrupt vector number assigned to the device. */ typedef struct { unsigned long numBARs; PCI_BAR_t BAR[MAX_PCI_BARS]; uint8_t PCICfgReg[256]; bool hasInterrupt; unsigned long intrVector; } PCIResourceInfo_t; /** * @struct dma_f2h_desc_hw * @brief DMA from FPGA to host descriptor hardware structure. * * This structure defines the layout of a single descriptor used in the DMA transfer * from FPGA to the host memory. It is packed to prevent any padding between the fields. * @param dma_f2h_desc_hw::f2h_desc_ctrl * Control flags for the descriptor. * @param dma_f2h_desc_hw::f2h_dma_len * Length of the DMA transfer. * @param dma_f2h_desc_hw::f2h_next_desc_addr_lo * Lower 32 bits of the next descriptor address. * @param dma_f2h_desc_hw::f2h_next_desc_addr_hi * Higher 32 bits of the next descriptor address. * @param dma_f2h_desc_hw::f2h_src_addr_lo * Lower 32 bits of the source address for the transfer. * @param dma_f2h_desc_hw::f2h_src_addr_hi * Higher 32 bits of the source address for the transfer. * @param dma_f2h_desc_hw::f2h_dest_addr_lo * Lower 32 bits of the destination address for the transfer. * @param dma_f2h_desc_hw::f2h_dest_addr_hi * Higher 32 bits of the destination address for the transfer. */ typedef struct dma_f2h_desc_hw { uint32_t f2h_desc_ctrl; uint32_t f2h_dma_len; uint32_t f2h_next_desc_addr_lo; uint32_t f2h_next_desc_addr_hi; uint32_t f2h_src_addr_lo; uint32_t f2h_src_addr_hi; uint32_t f2h_dest_addr_lo; uint32_t f2h_dest_addr_hi; } __attribute__((packed)) dma_f2h_desc_hw_t; /** * @struct dma_h2f_desc_hw * @brief DMA from FPGA to host descriptor hardware structure. * * This structure defines the layout of a single descriptor used in the DMA transfer * from FPGA to the host memory. It is packed to prevent any padding between the fields. * @param dma_h2f_desc_hw::h2f_desc_ctrl * Control flags for the descriptor. * @param dma_h2f_desc_hw::h2f_dma_len * Length of the DMA transfer. * @param dma_h2f_desc_hw::h2f_next_desc_addr_lo * Lower 32 bits of the next descriptor address. * @param dma_h2f_desc_hw::h2f_next_desc_addr_hi * Higher 32 bits of the next descriptor address. * @param dma_h2f_desc_hw::h2f_src_addr_lo * Lower 32 bits of the source address for the transfer. * @param dma_h2f_desc_hw::h2f_src_addr_hi * Higher 32 bits of the source address for the transfer. * @param dma_h2f_desc_hw::h2f_dest_addr_lo * Lower 32 bits of the destination address for the transfer. * @param dma_h2f_desc_hw::h2f_dest_addr_hi * Higher 32 bits of the destination address for the transfer. */ typedef struct dma_h2f_desc_hw { uint32_t h2f_desc_ctrl; uint32_t h2f_dma_len; uint32_t h2f_next_desc_addr_lo; uint32_t h2f_next_desc_addr_hi; uint32_t h2f_src_addr_lo; uint32_t h2f_src_addr_hi; uint32_t h2f_dest_addr_lo; uint32_t h2f_dest_addr_hi; } __attribute__((packed)) dma_h2f_desc_hw_t; /** * @struct ubuf_info * @brief Description of the ubuf_info struct. * This structure holds information about a user buffer, detailing its size, * the number of memory pages it spans, and the memory pages themselves. * @param ubuf_info::offset * Offset value. * @param ubuf_info::size * Size of the buffer. * @param ubuf_info::nr_pages * Number of pages. * @param ubuf_info::pages * Pointer to an array of struct page pointers. */ struct ubuf_info { int offset; size_t size; int nr_pages; struct page **pages; }; /** * @struct DMAChannel * @brief Structure to manage a DMA channel. * This structure contains all the necessary information to manage a DMA channel, * including state flags, buffer descriptors, spinlock for hardware access, and more. * @param DMAChannel::isDmaAddr64 * Set to true if 64-bit address support is required. * @param DMAChannel::numBDs * The number of buffer descriptors this channel has. * @param DMAChannel::startBD * The starting buffer descriptor index. * @param DMAChannel::hdwAccess * Spinlock to provide mutex protection when modifying SGDMA and IntCtrl registers. * @param DMAChannel::ubuf_info * Array of user buffer information structures. * @param DMAChannel::ubuf_sg_table * Array of scatter-gather tables for the user buffers. * @param DMAChannel::desc_cnt * The count of descriptors. * @param DMAChannel::fb_idx * Frame buffer index. * @param DMAChannel::dma_done * DMA completion flag. * @param DMAChannel::irq_vec * Array of interrupt vectors. * @param DMAChannel::num_irqs * Number of interrupts. * @param DMAChannel::desc_mode * Descriptor mode. * @param DMAChannel::dma_f2h_desc * Array of descriptors for FPGA to host transfers. * @param DMAChannel::dma_h2f_desc * Array of descriptors for host to FPGA transfers. * @param DMAChannel::dma_f2h_desc_handle * Array of handles for the FPGA to host descriptors. * @param DMAChannel::dma_h2f_desc_handle * Array of handles for the host to FPGA descriptors. * @param DMAChannel::direction * The direction of the DMA transfer. */ typedef struct DMAChannel { bool isDmaAddr64; /* set to true if asked for 64 bit address support */ unsigned long numBDs; /* how many buffer descriptors this channel has */ unsigned long startBD; /* whats the starting BD */ spinlock_t hdwAccess; /* spinlock to provide mutex protection when modifying SGDMA and IntCtrl regs */ struct ubuf_info *ubuf_info[MAX_NUM_DESCRIPTORS]; struct sg_table *ubuf_sg_table[MAX_NUM_DESCRIPTORS]; int f2h_desc_cnt; int h2f_desc_cnt; int max_desc_cnt; uint32_t f2h_num_sg_0; uint32_t h2f_num_sg_0; uint32_t f2h_total_desc_entry; uint32_t h2f_total_desc_entry; uint32_t f2h_size; uint32_t h2f_size; uint8_t h2f_dma_done; uint8_t f2h_dma_done; uint32_t irq_vec[32]; uint32_t num_irqs; uint8_t desc_mode; dma_f2h_desc_hw_t *dma_f2h_desc[MAX_NUM_DESCRIPTORS]; dma_h2f_desc_hw_t *dma_h2f_desc[MAX_NUM_DESCRIPTORS]; dma_addr_t dma_f2h_desc_handle[MAX_NUM_DESCRIPTORS]; dma_addr_t dma_h2f_desc_handle[MAX_NUM_DESCRIPTORS]; enum dma_transfer_direction direction; } DMAChannel_t; /** * @brief Structure to manage Scatter Gather DMA operations. * * This structure contains information necessary to manage the Scatter Gather DMA operations. * * @struct DMAOperations_t * @param DMAOperations_t::DmaOk * Indicates if adapters and everything are allocated (true) or not (false). * @param DMAOperations_t::WriteBurstSize * The maximum TLP size for a write operation (normally 128). * @param DMAOperations_t::ReadBurstSize * The maximum read request size (normally 512). * @param DMAOperations_t::chan * Array to track the SGDMA BDs used for the transfer. * @param DMAOperations_t::ReadWaitQ * Wait queue to park user's read() request while DMA'ing. * @param DMAOperations_t::WriteWaitQ * Wait queue to park user's write() request while DMA'ing. * @param DMAOperations_t::ipVer * SGDMA IP core version for register map changes. */ typedef struct { bool DmaOk; unsigned long WriteBurstSize; unsigned long ReadBurstSize; DMAChannel_t chan[NUM_DMA_CHANNELS]; wait_queue_head_t ReadWaitQ; wait_queue_head_t WriteWaitQ; unsigned long ipVer; } DMAOperations_t; /** * This is the private data for each board's BAR that is mapped in. * NOTE: each structure MUST have minor as the first entry because it * it tested by a void * to see what BAR it is - See mmap() */ typedef struct PCI_Dev_BAR { int bar; void *pci_addr; /* the physical bus address of the BAR (assigned by PCI system), used in mmap */ void *kvm_addr; /* the virtual address of a BAR mapped into kernel space, used in ioremap */ int memType; int dataSize; unsigned long len; unsigned long pci_start; /* info gathered from pci_resource_*() */ unsigned long pci_end; unsigned long pci_flags; } pci_dev_bar_t; /** * @brief Structure to manage PCIe board operations. * * This structure contains all the necessary information and controls to manage a PCIe board, * including driver and device information, mutex controls, PCI enumeration and link info, * interrupt info, BAR assignments, scatter gather DMA info, and operation control functions. * * @struct PCIE_Board * @param PCIE_Board::ID * PCI device ID of the board (e.g., 0x5303, 0xe235). * @param PCIE_Board::demoID * PCI subsystem device ID of the board (e.g., 0x3030, 0x5303). * @param PCIE_Board::demoType * DMA demo ID specific to this driver. * @param PCIE_Board::function * Function type (0=mem access (DMAtest), 1=ColorBars, 2=ImageMove). * @param PCIE_Board::boardType * Device ID for SC or ECP2M. * @param PCIE_Board::instanceNum * Tracks the number of identical board/demo devices in the system. * @param PCIE_Board::OpenToken * Atomic counter to ensure only one user opens the board at a time. * @param PCIE_Board::majorNum * Driver's major number for use in places where only the device exists. * @param PCIE_Board::minorNum * Specific minor number assigned to this board. * @param PCIE_Board::PCIeMaxPayloadSize * PCIe maximum payload size for memory write (MWr) into PC memory. * @param PCIE_Board::PCIeMaxReadReqSize * PCIe maximum read request size for memory read (MRd) from PC memory. * @param PCIE_Board::PCIeRCBSize * Root Complex Read Completion size (normally 64 bytes). * @param PCIE_Board::PCIeLinkWidth * PCIe link width (e.g., x1, x4). * @param PCIE_Board::PCICfgRegs * Array to store the standard PCI configuration registers for link settings. * @param PCIE_Board::IRQ * Interrupt line/vector (-1 if no interrupt support). * @param PCIE_Board::msi * Indicates if MSI interrupts are enabled (true) or regular INTx (false). * @param PCIE_Board::Dev_BARs * Database of valid, mapped BARs belonging to this board. * @param PCIE_Board::numBars * Number of valid BARs this board has. * @param PCIE_Board::mmapBAR * BAR used for memory mapping into user space (modifiable via IOCTL call). * @param PCIE_Board::ctrlBAR * BAR used for control access. * @param PCIE_Board::ctrlBARaddr * Memory address of the control BAR, ioremap'ed into driver space. * @param PCIE_Board::pdev * Pointer to the PCI core representation of the board. * @param PCIE_Board::cdev * Character device implemented by this driver. * @param PCIE_Board::DMA * Scatter Gather DMA information. * @param PCIE_Board::start_f2h_transfer * Function pointer to start a transfer from FPGA to host. * @param PCIE_Board::start_h2f_transfer * Function pointer to start a transfer from host to FPGA. * @param PCIE_Board::stop_transfer * Function pointer to stop a transfer. */ typedef struct PCIE_Board { // Driver and Device Information uint32_t ID; uint32_t demoID; uint32_t demoType; uint32_t function; uint32_t boardType; uint32_t instanceNum; // Driver Mutex Controls atomic_t OpenToken; // PCI Enumeration and Link Info uint32_t majorNum; uint32_t minorNum; uint32_t PCIeMaxPayloadSize; uint32_t PCIeMaxReadReqSize; uint32_t PCIeRCBSize; uint32_t PCIeLinkWidth; uint32_t PCICfgRegs[256/4]; // Interrupt Info uint32_t IRQ; bool msi; // BAR Assignments pci_dev_bar_t Dev_BARs[NUM_BARS]; uint8_t numBars; uint8_t mmapBAR; uint8_t ctrlBAR; void *ctrlBARaddr; struct pci_dev *pdev; struct cdev cdev; // Scatter Gather DMA Info DMAOperations_t DMA; // Operation control int (*start_f2h_transfer)(struct PCIE_Board *pBrd); int (*start_h2f_transfer)(struct PCIE_Board *pBrd); int (*stop_transfer)(struct PCIE_Board *pBrd); } pcie_board_t; /** * @brief Structure to manage PCIe DMA driver operations. * * This structure contains information necessary to manage the PCIe DMA driver, * including device numbers, board counts, sysfs entry points, and a database of installed PCIe boards. * * @struct PCIEDMA * @param PCIEDMA::drvrDevNum * Starting [MAJOR][MINOR] device number for this driver. * @param PCIEDMA::numBoards * Total number of boards controlled by the driver. * @param PCIEDMA::numPCIE_DMA * Count of the number of DMA boards found. * @param PCIEDMA::sysfs * Top entry point of pciedma in /sys/class. * @param PCIEDMA::Board * Database of LSC PCIe Evaluation Boards installed. */ struct PCIEDMA { dev_t drvrDevNum; uint8_t numBoards; uint8_t numPCIE_DMA; struct class *sysfs; pcie_board_t Board[NUM_BOARDS]; }; #endif //__BMD_H__