From 2c517dec956a005335c0b01272860cc9dfe76a2b Mon Sep 17 00:00:00 2001 From: Jeremy Lorelli Date: Mon, 16 Dec 2024 17:37:56 -0800 Subject: [PATCH] Merge data_dev_top and data_gpu_top Moved data_dev_top to common/driver and used the same symlink pattern that the other files use. --- common/driver/data_dev_top.c | 507 ++++++++++++++++++ .../driver/data_dev_top.h | 56 +- data_dev/driver/src/data_dev_top.c | 482 +---------------- data_dev/driver/src/data_dev_top.h | 56 +- data_gpu/driver/Makefile | 2 +- data_gpu/driver/src/data_dev_top.c | 1 + data_gpu/driver/src/data_dev_top.h | 1 + data_gpu/driver/src/data_gpu_top.c | 466 ---------------- 8 files changed, 539 insertions(+), 1032 deletions(-) create mode 100755 common/driver/data_dev_top.c rename data_gpu/driver/src/data_gpu_top.h => common/driver/data_dev_top.h (51%) mode change 100755 => 120000 data_dev/driver/src/data_dev_top.c mode change 100755 => 120000 data_dev/driver/src/data_dev_top.h create mode 120000 data_gpu/driver/src/data_dev_top.c create mode 120000 data_gpu/driver/src/data_dev_top.h delete mode 100755 data_gpu/driver/src/data_gpu_top.c diff --git a/common/driver/data_dev_top.c b/common/driver/data_dev_top.c new file mode 100755 index 00000000..a3bcaef2 --- /dev/null +++ b/common/driver/data_dev_top.c @@ -0,0 +1,507 @@ +/** + *----------------------------------------------------------------------------- + * Company : SLAC National Accelerator Laboratory + *----------------------------------------------------------------------------- + * Description: + * This file is part of the aes_stream_drivers package, responsible for defining + * top-level module types and functions for AES stream device drivers. It + * includes initialization and cleanup routines for the kernel module, as well + * as device probing, removal, and command execution functions. + * ---------------------------------------------------------------------------- + * This file is part of the aes_stream_drivers package. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the aes_stream_drivers package, including this file, may be + * copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE.txt file. + * ---------------------------------------------------------------------------- +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DATA_GPU +#include +#include +#include +#endif + +// Init Configuration values +int cfgTxCount = 1024; +int cfgRxCount = 1024; +int cfgSize = 0x20000; // 128kB +int cfgMode = BUFF_COHERENT; +int cfgCont = 1; +int cfgIrqHold = 10000; +int cfgIrqDis = 0; +int cfgBgThold0 = 0; +int cfgBgThold1 = 0; +int cfgBgThold2 = 0; +int cfgBgThold3 = 0; +int cfgBgThold4 = 0; +int cfgBgThold5 = 0; +int cfgBgThold6 = 0; +int cfgBgThold7 = 0; +int cfgDevName = 0; + +// Probe failure global flag used in driver init +// function to unregister driver +static int probeReturn = 0; + +struct DmaDevice gDmaDevices[MAX_DMA_DEVICES]; +// PCI device IDs +static struct pci_device_id DataDev_Ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_SLAC, PCI_DEVICE_ID_DDEV) }, + { 0, } +}; + +// Module Name +#define MOD_NAME "datadev" + +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, DataDev_Ids); +module_init(DataDev_Init); +module_exit(DataDev_Exit); + +/** + * struct pci_driver DataDevDriver - Device driver for AES data devices + * @name: Name of the driver + * @id_table: PCI device ID table for devices this driver can handle + * @probe: Callback for device probing. Initializes device instance. + * @remove: Callback for device removal. Cleans up device instance. + * + * This structure defines the PCI driver for AES data devices, handling + * device initialization, removal, and shutdown. It matches specific PCI + * devices to this driver using the id_table and provides callbacks for + * device lifecycle management. + */ +static struct pci_driver DataDevDriver = { + .name = MOD_NAME, + .id_table = DataDev_Ids, + .probe = DataDev_Probe, + .remove = DataDev_Remove, +}; + +/** + * DataDev_Init - Initialize the Data Device kernel module + * + * This function initializes the Data Device kernel module. It registers the PCI + * driver, initializes global variables, and sets up the device configuration. + * It checks for a probe failure and, if detected, unregisters the driver and + * returns the error. + * + * Return: 0 on success, negative error code on failure. + */ +int32_t DataDev_Init(void) { + int ret; + + /* Clear memory for all DMA devices */ + memset(gDmaDevices, 0, sizeof(struct DmaDevice) * MAX_DMA_DEVICES); + + pr_info("%s: Init\n", MOD_NAME); + + /* Initialize global variables */ + gCl = NULL; + gDmaDevCount = 0; + + /* Register PCI driver */ + ret = pci_register_driver(&DataDevDriver); + if (probeReturn != 0) { + pr_err("%s: Init: failure detected in init. Unregistering driver.\n", MOD_NAME); + pci_unregister_driver(&DataDevDriver); + return probeReturn; + } + + return ret; +} + +/** + * DataDev_Exit - Clean up and exit the Data Device kernel module + * + * This function is called when the Data Device kernel module is being removed + * from the kernel. It unregisters the PCI driver, effectively cleaning up + * any resources that were allocated during the operation of the module. + */ +void DataDev_Exit(void) { + // Log module exit + pr_info("%s: Exit.\n", MOD_NAME); + // Unregister the PCI driver to clean up + pci_unregister_driver(&DataDevDriver); +} + +/** + * DataDev_Probe - Probe for the AES stream device. + * @pdev: PCI device structure for the device. + * @id: Entry in data_dev_id table that matches with this device. + * + * This function is called by the kernel when a device matching the device ID table + * is found. It initializes the device, allocates required resources, and registers + * the device for use. It sets up the device-specific data, prepares the hardware + * for operation, and initializes any device-specific work structures. + * + * Return: 0 on success, negative error code on failure. + */ +int DataDev_Probe(struct pci_dev *pcidev, const struct pci_device_id *dev_id) { + struct DmaDevice *dev; + struct pci_device_id *id; + struct hardware_functions *hfunc; + + int32_t x; + int32_t axiWidth; + int ret; + + struct AxisG2Data *hwData; + + // Validate buffer mode configuration + if ( cfgMode != BUFF_COHERENT && cfgMode != BUFF_STREAM ) { + pr_err("%s: Probe: Invalid buffer mode = %i.\n", MOD_NAME, cfgMode); + return -EINVAL; // Return directly with an error code + } + + // Initialize hardware function pointers + hfunc = &(DataDev_functions); + + // Cast device ID for further operations + id = (struct pci_device_id *) dev_id; + + // Initialize driver data to indicate an empty slot + id->driver_data = -1; + + // Search for an available device slot + for (x = 0; x < MAX_DMA_DEVICES; x++) { + if (gDmaDevices[x].baseAddr == 0) { + id->driver_data = x; + break; + } + } + + // Check for device slots overflow + if (id->driver_data < 0) { + pr_err("%s: Probe: Too Many Devices.\n", MOD_NAME); + return -ENOMEM; // Return directly with an error code + } + dev = &gDmaDevices[id->driver_data]; + dev->index = id->driver_data; + + // Attempt to compose a unique device name based on configuration + if (cfgDevName != 0) { + // Utilize the PCI device bus number for unique device naming + // Helpful when multiple PCIe cards are installed in the same server + ret = snprintf(dev->devName, sizeof(dev->devName), "%s_%02x", MOD_NAME, pcidev->bus->number);//NOLINT + } else { + // Default to sequential naming based on the device's index + // Ensures uniqueness in a single card scenario + ret = snprintf(dev->devName, sizeof(dev->devName), "%s_%i", MOD_NAME, dev->index);//NOLINT + } + if (ret < 0 || ret >= sizeof(dev->devName)) { + pr_err("%s: Probe: Error in snprintf() while formatting device name\n", MOD_NAME); + probeReturn = -EINVAL; + goto err_pre_en; // Bail out, but clean up first + } + + // Activate the PCI device + ret = pci_enable_device(pcidev); + if (ret) { + pr_err("%s: Probe: pci_enable_device() = %i.\n", MOD_NAME, ret); + probeReturn = ret; // Return directly with error code + goto err_pre_en; // Bail out, but clean up first + } + pci_set_master(pcidev); // Set the device as bus master + + // Retrieve and store the base address and size of the device's register space + dev->baseAddr = pci_resource_start(pcidev, 0); + dev->baseSize = pci_resource_len(pcidev, 0); + + // Map the device's register space for use in the driver + if ( Dma_MapReg(dev) < 0 ) { + probeReturn = -ENOMEM; // Memory allocation error + goto err_post_en; + } + + // Initialize device configuration parameters + dev->cfgTxCount = cfgTxCount; // Transmit buffer count + dev->cfgRxCount = cfgRxCount; // Receive buffer count + dev->cfgSize = cfgSize; // Configuration size + dev->cfgMode = cfgMode; // Operation mode + dev->cfgCont = cfgCont; // Continuous operation flag + dev->cfgIrqHold = cfgIrqHold; // IRQ hold configuration + dev->cfgIrqDis = cfgIrqDis; // IRQ disable flag + dev->cfgBgThold[0] = cfgBgThold0; // Background threshold 0 + dev->cfgBgThold[1] = cfgBgThold1; // Background threshold 1 + dev->cfgBgThold[2] = cfgBgThold2; // Background threshold 2 + dev->cfgBgThold[3] = cfgBgThold3; // Background threshold 3 + dev->cfgBgThold[4] = cfgBgThold4; // Background threshold 4 + dev->cfgBgThold[5] = cfgBgThold5; // Background threshold 5 + dev->cfgBgThold[6] = cfgBgThold6; // Background threshold 6 + dev->cfgBgThold[7] = cfgBgThold7; // Background threshold 7 + + // Assign the IRQ number from the pci_dev structure + dev->irq = pcidev->irq; + + // Set basic device context + dev->pcidev = pcidev; // PCI device structure + dev->device = &(pcidev->dev); // Device structure + dev->hwFunc = hfunc; // Hardware function pointer + + // Initialize device memory regions + dev->reg = dev->base + AGEN2_OFF; // Register base address + dev->rwBase = dev->base + PHY_OFF; // Read/Write base address + dev->rwSize = (2*USER_SIZE) - PHY_OFF; // Read/Write region size + +#ifdef DATA_GPU + // GPU Init + Gpu_Init(dev, GPU_ASYNC_CORE_OFFSET); +#endif + + // Manage device reset cycle + dev_info(dev->device, "Init: Setting user reset\n"); + AxiVersion_SetUserReset(dev->base + AVER_OFF, true); // Set user reset + dev_info(dev->device, "Init: Clearing user reset\n"); + AxiVersion_SetUserReset(dev->base + AVER_OFF, false); // Clear user reset + + // Configure DMA based on AXI address width: 128bit desc, = 64-bit address map + if ((readl(dev->reg) & 0x10000) != 0) { + axiWidth = (readl(dev->reg + 0x34) >> 8) & 0xFF; // Extract AXI address width + + // Attempt to set DMA and coherent DMA masks based on AXI width + if (!dma_set_mask(dev->device, DMA_BIT_MASK(axiWidth))) { + dev_info(dev->device, "Init: Using %d-bit DMA mask.\n", axiWidth); + + if (!dma_set_coherent_mask(dev->device, DMA_BIT_MASK(axiWidth))) { + dev_info(dev->device, "Init: Using %d-bit coherent DMA mask.\n", axiWidth); + } else { + dev_err(dev->device, "Init: Failed to set coherent DMA mask.\n"); + probeReturn = -EINVAL; + goto err_post_en; + } + } else { + dev_err(dev->device, "Init: Failed to set DMA mask.\n"); + probeReturn = -EINVAL; + goto err_post_en; + } + } + + // Initialize common DMA functionalities + if (Dma_Init(dev) < 0) { + probeReturn = -ENOMEM; // Indicate memory allocation error + goto err_post_en; + } + + // Get hardware data structure + hwData = (struct AxisG2Data *)dev->hwData; + + // Log memory mapping information + dev_info(dev->device, "Init: Reg space mapped to 0x%p.\n", dev->reg); + dev_info(dev->device, "Init: User space mapped to 0x%p with size 0x%x.\n", dev->rwBase, dev->rwSize); + dev_info(dev->device, "Init: Top Register = 0x%x\n", readl(dev->reg)); + + // Finalize device probe successfully + gDmaDevCount++; // Increment global device count + probeReturn = 0; // Set successful return code + return probeReturn; // Return success + +err_post_en: + pci_disable_device(pcidev); // Disable PCI device on failure +err_pre_en: + memset(dev, 0, sizeof(*dev)); // Clear out the slot we took in gDmaDevices + return probeReturn; +} + +/** + * DataDev_Remove - Clean up and remove a DMA device + * @pcidev: PCI device structure + * + * This function is called by the PCI core when the device is removed from the system. + * It searches for the device in the global DMA devices array, decrements the global + * DMA device count, calls the common DMA clean function to free allocated resources, + * and disables the PCI device. + */ +void DataDev_Remove(struct pci_dev *pcidev) { + uint32_t x; + struct DmaDevice *dev = NULL; + + pr_info("%s: Remove: Remove called.\n", MOD_NAME); + + // Look for matching device + for (x = 0; x < MAX_DMA_DEVICES; x++) { + if (gDmaDevices[x].baseAddr == pci_resource_start(pcidev, 0)) { + dev = &gDmaDevices[x]; + break; + } + } + + // Device not found + if (dev == NULL) { + pr_err("%s: Remove: Device Not Found.\n", MOD_NAME); + return; + } + + // Decrement count + gDmaDevCount--; + + // Call common DMA clean function + Dma_Clean(dev); + + // Disable device + pci_disable_device(pcidev); + + pr_info("%s: Remove: Driver is unloaded.\n", MOD_NAME); +} + +/** + * DataDev_Command - Execute a command on the DMA device + * @dev: pointer to the DmaDevice structure + * @cmd: the command to be executed + * @arg: argument to the command, if any + * + * Executes a given command on the specified DMA device. The function + * handles different commands, including reading the AXI version via + * AVER_Get command and passing any other commands to the AxisG2_Command + * function for further processing. The function returns the result of + * the command execution, which could be a success indicator or an error code. + * + * Return: the result of the command execution. Returns -1 if the command + * is not recognized. + */ +int32_t DataDev_Command(struct DmaDevice *dev, uint32_t cmd, uint64_t arg) { + switch (cmd) { + +#ifdef DATA_GPU + // GPU Commands + // Handles adding or removing Nvidia memory based on the command specified. + case GPU_Add_Nvidia_Memory: + case GPU_Rem_Nvidia_Memory: + case GPU_Set_Write_Enable: + return Gpu_Command(dev, cmd, arg); +#endif + + case AVER_Get: + // AXI Version Read + return AxiVersion_Get(dev, dev->base + AVER_OFF, arg); + break; + + default: + // Delegate command to AxisG2 handler + return AxisG2_Command(dev, cmd, arg); + break; + } + return -1; +} + +/** + * DataDev_SeqShow - Display device information in sequence file + * @s: sequence file pointer to which the device information is written + * @dev: device structure containing the data to be displayed + * + * This function reads the AXI version from the device and displays it along + * with other device-specific information using the AxiVersion_Show and + * AxisG2_SeqShow functions. It's primarily used for proc file outputs, + * presenting a standardized view of device details for debugging or + * system monitoring. + */ +void DataDev_SeqShow(struct seq_file *s, struct DmaDevice *dev) { + struct AxiVersion aVer; + + // Read AXI version from device + AxiVersion_Read(dev, dev->base + AVER_OFF, &aVer); + + // Display AXI version information + AxiVersion_Show(s, dev, &aVer); + + // Display additional device-specific information + AxisG2_SeqShow(s, dev); + +#ifdef DATA_GPU + // Display DataGPU-specific state information + Gpu_Show(s, dev); +#endif +} + +/** + * struct hardware_functions - Hardware function pointers for Data Device operations. + * @irq: Pointer to the IRQ handler function. + * @init: Pointer to the initialization function for the device. + * @clear: Pointer to the function to clear device states or buffers. + * @enable: Pointer to the function to enable the device. + * @retRxBuffer: Pointer to the function for returning a received buffer. + * @sendBuffer: Pointer to the function for sending a buffer. + * @command: Pointer to the function for executing commands on the device. + * @seqShow: Pointer to the function for adding data to the proc dump. + * + * This structure defines a set of function pointers used for interacting + * with the hardware. Each member represents a specific operation that can + * be performed on the device, such as initialization, buffer management, + * and command execution. This allows for hardware-specific implementations + * of these operations while maintaining a common interface. + */ +struct hardware_functions DataDev_functions = { + .irq = AxisG2_Irq, + .init = AxisG2_Init, + .clear = AxisG2_Clear, + .enable = AxisG2_Enable, + .retRxBuffer = AxisG2_RetRxBuffer, + .sendBuffer = AxisG2_SendBuffer, + .command = DataDev_Command, + .seqShow = DataDev_SeqShow, +}; + +// Parameters +module_param(cfgTxCount, int, 0); +MODULE_PARM_DESC(cfgTxCount, "TX buffer count"); + +module_param(cfgRxCount, int, 0); +MODULE_PARM_DESC(cfgRxCount, "RX buffer count"); + +module_param(cfgSize, int, 0); +MODULE_PARM_DESC(cfgSize, "Rx/TX Buffer size"); + +module_param(cfgMode, int, 0); +MODULE_PARM_DESC(cfgMode, "RX buffer mode"); + +module_param(cfgCont, int, 0); +MODULE_PARM_DESC(cfgCont, "RX continue enable"); + +module_param(cfgIrqHold, int, 0); +MODULE_PARM_DESC(cfgIrqHold, "IRQ Holdoff"); + +module_param(cfgIrqDis, int, 0); +MODULE_PARM_DESC(cfgIrqDis, "IRQ Disable"); + +module_param(cfgBgThold0, int, 0); +MODULE_PARM_DESC(cfgBgThold0, "Buff Group Threshold 0"); + +module_param(cfgBgThold1, int, 0); +MODULE_PARM_DESC(cfgBgThold1, "Buff Group Threshold 1"); + +module_param(cfgBgThold2, int, 0); +MODULE_PARM_DESC(cfgBgThold2, "Buff Group Threshold 2"); + +module_param(cfgBgThold3, int, 0); +MODULE_PARM_DESC(cfgBgThold3, "Buff Group Threshold 3"); + +module_param(cfgBgThold4, int, 0); +MODULE_PARM_DESC(cfgBgThold4, "Buff Group Threshold 4"); + +module_param(cfgBgThold5, int, 0); +MODULE_PARM_DESC(cfgBgThold5, "Buff Group Threshold 5"); + +module_param(cfgBgThold6, int, 0); +MODULE_PARM_DESC(cfgBgThold6, "Buff Group Threshold 6"); + +module_param(cfgBgThold7, int, 0); +MODULE_PARM_DESC(cfgBgThold7, "Buff Group Threshold 7"); + +module_param(cfgDevName, int, 0); +MODULE_PARM_DESC(cfgDevName, "Device Name Formating Setting"); diff --git a/data_gpu/driver/src/data_gpu_top.h b/common/driver/data_dev_top.h similarity index 51% rename from data_gpu/driver/src/data_gpu_top.h rename to common/driver/data_dev_top.h index fee58225..dbe04f5a 100755 --- a/data_gpu/driver/src/data_gpu_top.h +++ b/common/driver/data_dev_top.h @@ -3,7 +3,7 @@ * Company : SLAC National Accelerator Laboratory *----------------------------------------------------------------------------- * Description: - * Defines the top-level module types and functions for the Data GPU Device driver. + * Defines the top-level module types and functions for the Data Device driver. * This driver is part of the aes_stream_drivers package. * ---------------------------------------------------------------------------- * This file is part of the aes_stream_drivers package. It is subject to @@ -16,42 +16,40 @@ * ---------------------------------------------------------------------------- **/ -#ifndef __DATA_GPU_TOP_H__ -#define __DATA_GPU_TOP_H__ +#ifndef __DATA_DEV_TOP_H__ +#define __DATA_DEV_TOP_H__ #include #include #include #include -/* Maximum number of DMA devices */ +/** Maximum number of DMA devices supported. */ #define MAX_DMA_DEVICES 32 -/* PCI IDs */ +/** PCI vendor and device identifiers. */ #define PCI_VENDOR_ID_SLAC 0x1a4a #define PCI_DEVICE_ID_DDEV 0x2030 -/* Memory mapping offsets and sizes */ -#define AGEN2_OFF 0x00000000 -#define AGEN2_SIZE 0x00010000 -#define PHY_OFF 0x00010000 -#define PHY_SIZE 0x00010000 -#define AVER_OFF 0x00020000 -#define AVER_SIZE 0x00010000 -#define PROM_OFF 0x00030000 -#define PROM_SIZE 0x00050000 -#define USER_OFF 0x00800000 -#define USER_SIZE 0x00800000 - -/* Function prototypes */ -int32_t DataGpu_Init(void); -void DataGpu_Exit(void); -int DataGpu_Probe(struct pci_dev *pcidev, const struct pci_device_id *dev_id); -void DataGpu_Remove(struct pci_dev *pcidev); -int32_t DataGpu_Command(struct DmaDevice *dev, uint32_t cmd, uint64_t arg); -void DataGpu_SeqShow(struct seq_file *s, struct DmaDevice *dev); - -/* Hardware function operations */ -extern struct hardware_functions DataGpu_functions; - -#endif /* __DATA_GPU_TOP_H__ */ +/** Address map for device registers. */ +#define AGEN2_OFF 0x00000000 /**< DMAv2 Engine Offset */ +#define AGEN2_SIZE 0x00010000 /**< DMAv2 Engine Size */ +#define PHY_OFF 0x00010000 /**< PCIe PHY Offset */ +#define PHY_SIZE 0x00010000 /**< PCIe PHY Size */ +#define AVER_OFF 0x00020000 /**< AxiVersion Offset */ +#define AVER_SIZE 0x00010000 /**< AxiVersion Size */ +#define PROM_OFF 0x00030000 /**< PROM Offset */ +#define PROM_SIZE 0x00050000 /**< PROM Size */ +#define USER_OFF 0x00800000 /**< User Space Offset */ +#define USER_SIZE 0x00800000 /**< User Space Size */ + +// Function prototypes +int32_t DataDev_Init(void); +void DataDev_Exit(void); +int DataDev_Probe(struct pci_dev *pcidev, const struct pci_device_id *dev_id); +void DataDev_Remove(struct pci_dev *pcidev); +int32_t DataDev_Command(struct DmaDevice *dev, uint32_t cmd, uint64_t arg); +void DataDev_SeqShow(struct seq_file *s, struct DmaDevice *dev); +extern struct hardware_functions DataDev_functions; + +#endif // __DATA_DEV_TOP_H__ diff --git a/data_dev/driver/src/data_dev_top.c b/data_dev/driver/src/data_dev_top.c deleted file mode 100755 index 20e8a935..00000000 --- a/data_dev/driver/src/data_dev_top.c +++ /dev/null @@ -1,481 +0,0 @@ -/** - *----------------------------------------------------------------------------- - * Company : SLAC National Accelerator Laboratory - *----------------------------------------------------------------------------- - * Description: - * This file is part of the aes_stream_drivers package, responsible for defining - * top-level module types and functions for AES stream device drivers. It - * includes initialization and cleanup routines for the kernel module, as well - * as device probing, removal, and command execution functions. - * ---------------------------------------------------------------------------- - * This file is part of the aes_stream_drivers package. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the aes_stream_drivers package, including this file, may be - * copied, modified, propagated, or distributed except according to the terms - * contained in the LICENSE.txt file. - * ---------------------------------------------------------------------------- -**/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Init Configuration values -int cfgTxCount = 1024; -int cfgRxCount = 1024; -int cfgSize = 0x20000; // 128kB -int cfgMode = BUFF_COHERENT; -int cfgCont = 1; -int cfgIrqHold = 10000; -int cfgIrqDis = 0; -int cfgBgThold0 = 0; -int cfgBgThold1 = 0; -int cfgBgThold2 = 0; -int cfgBgThold3 = 0; -int cfgBgThold4 = 0; -int cfgBgThold5 = 0; -int cfgBgThold6 = 0; -int cfgBgThold7 = 0; -int cfgDevName = 0; - -// Probe failure global flag used in driver init -// function to unregister driver -static int probeReturn = 0; - -struct DmaDevice gDmaDevices[MAX_DMA_DEVICES]; -// PCI device IDs -static struct pci_device_id DataDev_Ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_SLAC, PCI_DEVICE_ID_DDEV) }, - { 0, } -}; - -// Module Name -#define MOD_NAME "datadev" - -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, DataDev_Ids); -module_init(DataDev_Init); -module_exit(DataDev_Exit); - -/** - * struct pci_driver DataDevDriver - Device driver for AES data devices - * @name: Name of the driver - * @id_table: PCI device ID table for devices this driver can handle - * @probe: Callback for device probing. Initializes device instance. - * @remove: Callback for device removal. Cleans up device instance. - * - * This structure defines the PCI driver for AES data devices, handling - * device initialization, removal, and shutdown. It matches specific PCI - * devices to this driver using the id_table and provides callbacks for - * device lifecycle management. - */ -static struct pci_driver DataDevDriver = { - .name = MOD_NAME, - .id_table = DataDev_Ids, - .probe = DataDev_Probe, - .remove = DataDev_Remove, -}; - -/** - * DataDev_Init - Initialize the Data Device kernel module - * - * This function initializes the Data Device kernel module. It registers the PCI - * driver, initializes global variables, and sets up the device configuration. - * It checks for a probe failure and, if detected, unregisters the driver and - * returns the error. - * - * Return: 0 on success, negative error code on failure. - */ -int32_t DataDev_Init(void) { - int ret; - - /* Clear memory for all DMA devices */ - memset(gDmaDevices, 0, sizeof(struct DmaDevice) * MAX_DMA_DEVICES); - - pr_info("%s: Init\n", MOD_NAME); - - /* Initialize global variables */ - gCl = NULL; - gDmaDevCount = 0; - - /* Register PCI driver */ - ret = pci_register_driver(&DataDevDriver); - if (probeReturn != 0) { - pr_err("%s: Init: failure detected in init. Unregistering driver.\n", MOD_NAME); - pci_unregister_driver(&DataDevDriver); - return probeReturn; - } - - return ret; -} - -/** - * DataDev_Exit - Clean up and exit the Data Device kernel module - * - * This function is called when the Data Device kernel module is being removed - * from the kernel. It unregisters the PCI driver, effectively cleaning up - * any resources that were allocated during the operation of the module. - */ -void DataDev_Exit(void) { - // Log module exit - pr_info("%s: Exit.\n", MOD_NAME); - // Unregister the PCI driver to clean up - pci_unregister_driver(&DataDevDriver); -} - -/** - * DataDev_Probe - Probe for the AES stream device. - * @pdev: PCI device structure for the device. - * @id: Entry in data_dev_id table that matches with this device. - * - * This function is called by the kernel when a device matching the device ID table - * is found. It initializes the device, allocates required resources, and registers - * the device for use. It sets up the device-specific data, prepares the hardware - * for operation, and initializes any device-specific work structures. - * - * Return: 0 on success, negative error code on failure. - */ -int DataDev_Probe(struct pci_dev *pcidev, const struct pci_device_id *dev_id) { - struct DmaDevice *dev; - struct pci_device_id *id; - struct hardware_functions *hfunc; - - int32_t x; - int32_t axiWidth; - int ret; - - struct AxisG2Data *hwData; - - // Validate buffer mode configuration - if ( cfgMode != BUFF_COHERENT && cfgMode != BUFF_STREAM ) { - pr_err("%s: Probe: Invalid buffer mode = %i.\n", MOD_NAME, cfgMode); - return -EINVAL; // Return directly with an error code - } - - // Initialize hardware function pointers - hfunc = &(DataDev_functions); - - // Cast device ID for further operations - id = (struct pci_device_id *) dev_id; - - // Initialize driver data to indicate an empty slot - id->driver_data = -1; - - // Search for an available device slot - for (x = 0; x < MAX_DMA_DEVICES; x++) { - if (gDmaDevices[x].baseAddr == 0) { - id->driver_data = x; - break; - } - } - - // Check for device slots overflow - if (id->driver_data < 0) { - pr_err("%s: Probe: Too Many Devices.\n", MOD_NAME); - return -ENOMEM; // Return directly with an error code - } - dev = &gDmaDevices[id->driver_data]; - dev->index = id->driver_data; - - // Attempt to compose a unique device name based on configuration - if (cfgDevName != 0) { - // Utilize the PCI device bus number for unique device naming - // Helpful when multiple PCIe cards are installed in the same server - ret = snprintf(dev->devName, sizeof(dev->devName), "%s_%02x", MOD_NAME, pcidev->bus->number);//NOLINT - } else { - // Default to sequential naming based on the device's index - // Ensures uniqueness in a single card scenario - ret = snprintf(dev->devName, sizeof(dev->devName), "%s_%i", MOD_NAME, dev->index);//NOLINT - } - if (ret < 0 || ret >= sizeof(dev->devName)) { - pr_err("%s: Probe: Error in snprintf() while formatting device name\n", MOD_NAME); - probeReturn = -EINVAL; - goto err_pre_en; // Bail out, but clean up first - } - - // Activate the PCI device - ret = pci_enable_device(pcidev); - if (ret) { - pr_err("%s: Probe: pci_enable_device() = %i.\n", MOD_NAME, ret); - probeReturn = ret; // Return directly with error code - goto err_pre_en; // Bail out, but clean up first - } - pci_set_master(pcidev); // Set the device as bus master - - // Retrieve and store the base address and size of the device's register space - dev->baseAddr = pci_resource_start(pcidev, 0); - dev->baseSize = pci_resource_len(pcidev, 0); - - // Map the device's register space for use in the driver - if ( Dma_MapReg(dev) < 0 ) { - probeReturn = -ENOMEM; // Memory allocation error - goto err_post_en; - } - - // Initialize device configuration parameters - dev->cfgTxCount = cfgTxCount; // Transmit buffer count - dev->cfgRxCount = cfgRxCount; // Receive buffer count - dev->cfgSize = cfgSize; // Configuration size - dev->cfgMode = cfgMode; // Operation mode - dev->cfgCont = cfgCont; // Continuous operation flag - dev->cfgIrqHold = cfgIrqHold; // IRQ hold configuration - dev->cfgIrqDis = cfgIrqDis; // IRQ disable flag - dev->cfgBgThold[0] = cfgBgThold0; // Background threshold 0 - dev->cfgBgThold[1] = cfgBgThold1; // Background threshold 1 - dev->cfgBgThold[2] = cfgBgThold2; // Background threshold 2 - dev->cfgBgThold[3] = cfgBgThold3; // Background threshold 3 - dev->cfgBgThold[4] = cfgBgThold4; // Background threshold 4 - dev->cfgBgThold[5] = cfgBgThold5; // Background threshold 5 - dev->cfgBgThold[6] = cfgBgThold6; // Background threshold 6 - dev->cfgBgThold[7] = cfgBgThold7; // Background threshold 7 - - // Assign the IRQ number from the pci_dev structure - dev->irq = pcidev->irq; - - // Set basic device context - dev->pcidev = pcidev; // PCI device structure - dev->device = &(pcidev->dev); // Device structure - dev->hwFunc = hfunc; // Hardware function pointer - - // Initialize device memory regions - dev->reg = dev->base + AGEN2_OFF; // Register base address - dev->rwBase = dev->base + PHY_OFF; // Read/Write base address - dev->rwSize = (2*USER_SIZE) - PHY_OFF; // Read/Write region size - - // Manage device reset cycle - dev_info(dev->device, "Init: Setting user reset\n"); - AxiVersion_SetUserReset(dev->base + AVER_OFF, true); // Set user reset - dev_info(dev->device, "Init: Clearing user reset\n"); - AxiVersion_SetUserReset(dev->base + AVER_OFF, false); // Clear user reset - - // Configure DMA based on AXI address width: 128bit desc, = 64-bit address map - if ((readl(dev->reg) & 0x10000) != 0) { - axiWidth = (readl(dev->reg + 0x34) >> 8) & 0xFF; // Extract AXI address width - - // Attempt to set DMA and coherent DMA masks based on AXI width - if (!dma_set_mask(dev->device, DMA_BIT_MASK(axiWidth))) { - dev_info(dev->device, "Init: Using %d-bit DMA mask.\n", axiWidth); - - if (!dma_set_coherent_mask(dev->device, DMA_BIT_MASK(axiWidth))) { - dev_info(dev->device, "Init: Using %d-bit coherent DMA mask.\n", axiWidth); - } else { - dev_err(dev->device, "Init: Failed to set coherent DMA mask.\n"); - probeReturn = -EINVAL; - goto err_post_en; - } - } else { - dev_err(dev->device, "Init: Failed to set DMA mask.\n"); - probeReturn = -EINVAL; - goto err_post_en; - } - } - - // Initialize common DMA functionalities - if (Dma_Init(dev) < 0) { - probeReturn = -ENOMEM; // Indicate memory allocation error - goto err_post_en; - } - - // Get hardware data structure - hwData = (struct AxisG2Data *)dev->hwData; - - // Log memory mapping information - dev_info(dev->device, "Init: Reg space mapped to 0x%p.\n", dev->reg); - dev_info(dev->device, "Init: User space mapped to 0x%p with size 0x%x.\n", dev->rwBase, dev->rwSize); - dev_info(dev->device, "Init: Top Register = 0x%x\n", readl(dev->reg)); - - // Finalize device probe successfully - gDmaDevCount++; // Increment global device count - probeReturn = 0; // Set successful return code - return probeReturn; // Return success - -err_post_en: - pci_disable_device(pcidev); // Disable PCI device on failure -err_pre_en: - memset(dev, 0, sizeof(*dev)); // Clear out the slot we took in gDmaDevices - return probeReturn; -} - -/** - * DataDev_Remove - Clean up and remove a DMA device - * @pcidev: PCI device structure - * - * This function is called by the PCI core when the device is removed from the system. - * It searches for the device in the global DMA devices array, decrements the global - * DMA device count, calls the common DMA clean function to free allocated resources, - * and disables the PCI device. - */ -void DataDev_Remove(struct pci_dev *pcidev) { - uint32_t x; - struct DmaDevice *dev = NULL; - - pr_info("%s: Remove: Remove called.\n", MOD_NAME); - - // Look for matching device - for (x = 0; x < MAX_DMA_DEVICES; x++) { - if (gDmaDevices[x].baseAddr == pci_resource_start(pcidev, 0)) { - dev = &gDmaDevices[x]; - break; - } - } - - // Device not found - if (dev == NULL) { - pr_err("%s: Remove: Device Not Found.\n", MOD_NAME); - return; - } - - // Decrement count - gDmaDevCount--; - - // Call common DMA clean function - Dma_Clean(dev); - - // Disable device - pci_disable_device(pcidev); - - pr_info("%s: Remove: Driver is unloaded.\n", MOD_NAME); -} - -/** - * DataDev_Command - Execute a command on the DMA device - * @dev: pointer to the DmaDevice structure - * @cmd: the command to be executed - * @arg: argument to the command, if any - * - * Executes a given command on the specified DMA device. The function - * handles different commands, including reading the AXI version via - * AVER_Get command and passing any other commands to the AxisG2_Command - * function for further processing. The function returns the result of - * the command execution, which could be a success indicator or an error code. - * - * Return: the result of the command execution. Returns -1 if the command - * is not recognized. - */ -int32_t DataDev_Command(struct DmaDevice *dev, uint32_t cmd, uint64_t arg) { - switch (cmd) { - case AVER_Get: - // AXI Version Read - return AxiVersion_Get(dev, dev->base + AVER_OFF, arg); - break; - - default: - // Delegate command to AxisG2 handler - return AxisG2_Command(dev, cmd, arg); - break; - } - return -1; -} - -/** - * DataDev_SeqShow - Display device information in sequence file - * @s: sequence file pointer to which the device information is written - * @dev: device structure containing the data to be displayed - * - * This function reads the AXI version from the device and displays it along - * with other device-specific information using the AxiVersion_Show and - * AxisG2_SeqShow functions. It's primarily used for proc file outputs, - * presenting a standardized view of device details for debugging or - * system monitoring. - */ -void DataDev_SeqShow(struct seq_file *s, struct DmaDevice *dev) { - struct AxiVersion aVer; - - // Read AXI version from device - AxiVersion_Read(dev, dev->base + AVER_OFF, &aVer); - - // Display AXI version information - AxiVersion_Show(s, dev, &aVer); - - // Display additional device-specific information - AxisG2_SeqShow(s, dev); -} - -/** - * struct hardware_functions - Hardware function pointers for Data Device operations. - * @irq: Pointer to the IRQ handler function. - * @init: Pointer to the initialization function for the device. - * @clear: Pointer to the function to clear device states or buffers. - * @enable: Pointer to the function to enable the device. - * @retRxBuffer: Pointer to the function for returning a received buffer. - * @sendBuffer: Pointer to the function for sending a buffer. - * @command: Pointer to the function for executing commands on the device. - * @seqShow: Pointer to the function for adding data to the proc dump. - * - * This structure defines a set of function pointers used for interacting - * with the hardware. Each member represents a specific operation that can - * be performed on the device, such as initialization, buffer management, - * and command execution. This allows for hardware-specific implementations - * of these operations while maintaining a common interface. - */ -struct hardware_functions DataDev_functions = { - .irq = AxisG2_Irq, - .init = AxisG2_Init, - .clear = AxisG2_Clear, - .enable = AxisG2_Enable, - .retRxBuffer = AxisG2_RetRxBuffer, - .sendBuffer = AxisG2_SendBuffer, - .command = DataDev_Command, - .seqShow = DataDev_SeqShow, -}; - -// Parameters -module_param(cfgTxCount, int, 0); -MODULE_PARM_DESC(cfgTxCount, "TX buffer count"); - -module_param(cfgRxCount, int, 0); -MODULE_PARM_DESC(cfgRxCount, "RX buffer count"); - -module_param(cfgSize, int, 0); -MODULE_PARM_DESC(cfgSize, "Rx/TX Buffer size"); - -module_param(cfgMode, int, 0); -MODULE_PARM_DESC(cfgMode, "RX buffer mode"); - -module_param(cfgCont, int, 0); -MODULE_PARM_DESC(cfgCont, "RX continue enable"); - -module_param(cfgIrqHold, int, 0); -MODULE_PARM_DESC(cfgIrqHold, "IRQ Holdoff"); - -module_param(cfgIrqDis, int, 0); -MODULE_PARM_DESC(cfgIrqDis, "IRQ Disable"); - -module_param(cfgBgThold0, int, 0); -MODULE_PARM_DESC(cfgBgThold0, "Buff Group Threshold 0"); - -module_param(cfgBgThold1, int, 0); -MODULE_PARM_DESC(cfgBgThold1, "Buff Group Threshold 1"); - -module_param(cfgBgThold2, int, 0); -MODULE_PARM_DESC(cfgBgThold2, "Buff Group Threshold 2"); - -module_param(cfgBgThold3, int, 0); -MODULE_PARM_DESC(cfgBgThold3, "Buff Group Threshold 3"); - -module_param(cfgBgThold4, int, 0); -MODULE_PARM_DESC(cfgBgThold4, "Buff Group Threshold 4"); - -module_param(cfgBgThold5, int, 0); -MODULE_PARM_DESC(cfgBgThold5, "Buff Group Threshold 5"); - -module_param(cfgBgThold6, int, 0); -MODULE_PARM_DESC(cfgBgThold6, "Buff Group Threshold 6"); - -module_param(cfgBgThold7, int, 0); -MODULE_PARM_DESC(cfgBgThold7, "Buff Group Threshold 7"); - -module_param(cfgDevName, int, 0); -MODULE_PARM_DESC(cfgDevName, "Device Name Formating Setting"); diff --git a/data_dev/driver/src/data_dev_top.c b/data_dev/driver/src/data_dev_top.c new file mode 120000 index 00000000..ddd4cad3 --- /dev/null +++ b/data_dev/driver/src/data_dev_top.c @@ -0,0 +1 @@ +../../../common/driver/data_dev_top.c \ No newline at end of file diff --git a/data_dev/driver/src/data_dev_top.h b/data_dev/driver/src/data_dev_top.h deleted file mode 100755 index dbe04f5a..00000000 --- a/data_dev/driver/src/data_dev_top.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - *----------------------------------------------------------------------------- - * Company : SLAC National Accelerator Laboratory - *----------------------------------------------------------------------------- - * Description: - * Defines the top-level module types and functions for the Data Device driver. - * This driver is part of the aes_stream_drivers package. - * ---------------------------------------------------------------------------- - * This file is part of the aes_stream_drivers package. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the aes_stream_drivers package, including this file, may be - * copied, modified, propagated, or distributed except according to the terms - * contained in the LICENSE.txt file. - * ---------------------------------------------------------------------------- -**/ - -#ifndef __DATA_DEV_TOP_H__ -#define __DATA_DEV_TOP_H__ - -#include -#include -#include -#include - -/** Maximum number of DMA devices supported. */ -#define MAX_DMA_DEVICES 32 - -/** PCI vendor and device identifiers. */ -#define PCI_VENDOR_ID_SLAC 0x1a4a -#define PCI_DEVICE_ID_DDEV 0x2030 - -/** Address map for device registers. */ -#define AGEN2_OFF 0x00000000 /**< DMAv2 Engine Offset */ -#define AGEN2_SIZE 0x00010000 /**< DMAv2 Engine Size */ -#define PHY_OFF 0x00010000 /**< PCIe PHY Offset */ -#define PHY_SIZE 0x00010000 /**< PCIe PHY Size */ -#define AVER_OFF 0x00020000 /**< AxiVersion Offset */ -#define AVER_SIZE 0x00010000 /**< AxiVersion Size */ -#define PROM_OFF 0x00030000 /**< PROM Offset */ -#define PROM_SIZE 0x00050000 /**< PROM Size */ -#define USER_OFF 0x00800000 /**< User Space Offset */ -#define USER_SIZE 0x00800000 /**< User Space Size */ - -// Function prototypes -int32_t DataDev_Init(void); -void DataDev_Exit(void); -int DataDev_Probe(struct pci_dev *pcidev, const struct pci_device_id *dev_id); -void DataDev_Remove(struct pci_dev *pcidev); -int32_t DataDev_Command(struct DmaDevice *dev, uint32_t cmd, uint64_t arg); -void DataDev_SeqShow(struct seq_file *s, struct DmaDevice *dev); -extern struct hardware_functions DataDev_functions; - -#endif // __DATA_DEV_TOP_H__ diff --git a/data_dev/driver/src/data_dev_top.h b/data_dev/driver/src/data_dev_top.h new file mode 120000 index 00000000..39a3f0cc --- /dev/null +++ b/data_dev/driver/src/data_dev_top.h @@ -0,0 +1 @@ +../../../common/driver/data_dev_top.h \ No newline at end of file diff --git a/data_gpu/driver/Makefile b/data_gpu/driver/Makefile index 94be4efd..84b75a7b 100644 --- a/data_gpu/driver/Makefile +++ b/data_gpu/driver/Makefile @@ -58,7 +58,7 @@ endif # Compiler flags: Include paths and definitions. ccflags-y += -I$(HOME)/src -ccflags-y += -DDMA_IN_KERNEL=1 -DGITV=\"$(GITV)\" +ccflags-y += -DDMA_IN_KERNEL=1 -DGITV=\"$(GITV)\" -DDATA_GPU=1 ccflags-y += -I$(NVIDIA_DRIVERS)/nvidia # Object files for the module. diff --git a/data_gpu/driver/src/data_dev_top.c b/data_gpu/driver/src/data_dev_top.c new file mode 120000 index 00000000..ddd4cad3 --- /dev/null +++ b/data_gpu/driver/src/data_dev_top.c @@ -0,0 +1 @@ +../../../common/driver/data_dev_top.c \ No newline at end of file diff --git a/data_gpu/driver/src/data_dev_top.h b/data_gpu/driver/src/data_dev_top.h new file mode 120000 index 00000000..39a3f0cc --- /dev/null +++ b/data_gpu/driver/src/data_dev_top.h @@ -0,0 +1 @@ +../../../common/driver/data_dev_top.h \ No newline at end of file diff --git a/data_gpu/driver/src/data_gpu_top.c b/data_gpu/driver/src/data_gpu_top.c deleted file mode 100755 index 8aef9804..00000000 --- a/data_gpu/driver/src/data_gpu_top.c +++ /dev/null @@ -1,466 +0,0 @@ -/** - *----------------------------------------------------------------------------- - * Company : SLAC National Accelerator Laboratory - *----------------------------------------------------------------------------- - * Description: - * This file is part of the aes_stream_drivers package, responsible for defining - * top-level module types and functions for AES stream device drivers. It - * includes initialization and cleanup routines for the kernel module, as well - * as device probing, removal, and command execution functions. - * ---------------------------------------------------------------------------- - * This file is part of the aes_stream_drivers package. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the aes_stream_drivers package, including this file, may be - * copied, modified, propagated, or distributed except according to the terms - * contained in the LICENSE.txt file. - * ---------------------------------------------------------------------------- -**/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Configuration values initialization. - * These values are used to set up the DMA (Direct Memory Access) transfer settings. - */ -int cfgTxCount = 1024; // Transmit buffer count -int cfgRxCount = 1024; // Receive buffer count -int cfgSize = 0x20000; // Size of the buffer: 128kB -int cfgMode = BUFF_COHERENT; // Buffer mode: coherent -int cfgCont = 1; // Continuous operation flag -int cfgDevName = 0; - -/* - * Global array of DMA devices. - * This array holds the configuration and status of each DMA device handled by this driver. - */ -struct DmaDevice gDmaDevices[MAX_DMA_DEVICES]; - -/* - * PCI device identification array. - * This array is used by the kernel to match this driver to the specific hardware based on PCI IDs. - */ -static struct pci_device_id DataGpu_Ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_SLAC, PCI_DEVICE_ID_DDEV) }, // Device ID for SLAC vendor, specific device - { 0, } // Terminator for the ID list -}; - -/* Module metadata definitions */ -#define MOD_NAME "datagpu" // Name of the module -MODULE_LICENSE("GPL"); // License type: GPL for open source compliance -MODULE_DEVICE_TABLE(pci, DataGpu_Ids); // Associate the PCI ID table with this module -module_init(DataGpu_Init); // Initialize the module with DataGpu_Init function -module_exit(DataGpu_Exit); // Clean-up the module with DataGpu_Exit function - -/* - * PCI driver structure definition. - * This structure contains callback functions and device IDs for the DataGpu driver. - */ -static struct pci_driver DataGpuDriver = { - .name = MOD_NAME, // Name of the driver - .id_table = DataGpu_Ids, // PCI device ID table - .probe = DataGpu_Probe, // Probe function for device discovery - .remove = DataGpu_Remove, // Remove function for device disconnection -}; - -/** - * DataGpu_Init - Initialize the DataGpu Kernel Module. - * - * This function initializes the Data GPU kernel module. It allocates and clears - * memory for all DMA devices managed by this module, initializes global variables, - * and registers the module with the PCI subsystem as a driver for specified devices. - * - * Return: Zero on success, negative error code on failure. - */ -int32_t DataGpu_Init(void) { - /* Clear memory for all DMA devices to reset their configuration. */ - memset(gDmaDevices, 0, sizeof(struct DmaDevice) * MAX_DMA_DEVICES); - - /* Log module initialization with the kernel logging system. */ - pr_info("%s: Init\n", MOD_NAME); - - /* Initialize global pointers and counters. */ - gCl = NULL; // Clear global class pointer. - gDmaDevCount = 0; // Reset the count of DMA devices managed by this module. - - /* Register this driver with the PCI subsystem to handle devices matching our IDs. */ - return pci_register_driver(&DataGpuDriver); -} - -/** - * DataGpu_Exit - Clean up the DataGpu Kernel Module. - * - * This function is called when the DataGpu kernel module is being removed - * from the system. It unregisters the driver from the PCI subsystem and - * logs the module exit with the kernel logging system. - */ -void DataGpu_Exit(void) { - /* Log module exit with the kernel logging system. */ - pr_info("%s: Exit.\n", MOD_NAME); - - /* Unregister this driver from the PCI subsystem. */ - pci_unregister_driver(&DataGpuDriver); -} - -/** - * DataGpu_Probe - Probe function for DataGpu devices. - * @pcidev: PCI device structure provided by the kernel. - * @dev_id: PCI device ID that matches this driver. - * - * This function is called by the kernel when a device that matches the ID table - * for this driver is found. It initializes the device, sets up DMA and other - * hardware functionalities, and prepares the device for use. - * - * Return: 0 on success, negative error code on failure. - */ -int DataGpu_Probe(struct pci_dev *pcidev, const struct pci_device_id *dev_id) { - struct DmaDevice *dev; - struct pci_device_id *id; - struct hardware_functions *hfunc; - - int32_t x; - int32_t axiWidth; - int ret; - int probeReturn = 0; - - // Validate buffer mode configuration - if ( cfgMode != BUFF_COHERENT && cfgMode != BUFF_STREAM ) { - pr_err("%s: Probe: Invalid buffer mode = %i.\n", MOD_NAME, cfgMode); - return -EINVAL; // Return directly with an error code - } - - // Initialize hardware function pointers - hfunc = &(DataGpu_functions); - - // Cast device ID for further operations - id = (struct pci_device_id *) dev_id; - - // Initialize driver data to indicate an empty slot - id->driver_data = -1; - - // Search for an available device slot - for (x = 0; x < MAX_DMA_DEVICES; x++) { - if (gDmaDevices[x].baseAddr == 0) { - id->driver_data = x; - break; - } - } - - // Check for device slots overflow - if (id->driver_data < 0) { - pr_err("%s: Probe: Too Many Devices.\n", MOD_NAME); - return -ENOMEM; // Return directly with an error code - } - dev = &gDmaDevices[id->driver_data]; - dev->index = id->driver_data; - - // Attempt to compose a unique device name based on configuration - if (cfgDevName != 0) { - // Utilize the PCI device bus number for unique device naming - // Helpful when multiple PCIe cards are installed in the same server - ret = snprintf(dev->devName, sizeof(dev->devName), "%s_%02x", MOD_NAME, pcidev->bus->number);//NOLINT - } else { - // Default to sequential naming based on the device's index - // Ensures uniqueness in a single card scenario - ret = snprintf(dev->devName, sizeof(dev->devName), "%s_%i", MOD_NAME, dev->index);//NOLINT - } - if (ret < 0 || ret >= sizeof(dev->devName)) { - pr_err("%s: Probe: Error in snprintf() while formatting device name\n", MOD_NAME); - probeReturn = -EINVAL; // Return directly with an error code - goto err_pre_en; - } - - // Activate the PCI device - ret = pci_enable_device(pcidev); - if (ret) { - pr_err("%s: Probe: pci_enable_device() = %i.\n", MOD_NAME, ret); - probeReturn = ret; // Return with error code - goto err_pre_en; - } - pci_set_master(pcidev); // Set the device as bus master - - // Retrieve and store the base address and size of the device's register space - dev->baseAddr = pci_resource_start(pcidev, 0); - dev->baseSize = pci_resource_len(pcidev, 0); - - // Map the device's register space for use in the driver - if ( Dma_MapReg(dev) < 0 ) { - probeReturn = -ENOMEM; // Memory allocation error - goto err_post_en; - } - - // Initialize device configuration parameters - dev->cfgTxCount = cfgTxCount; - dev->cfgRxCount = cfgRxCount; - dev->cfgSize = cfgSize; - dev->cfgMode = cfgMode; - dev->cfgCont = cfgCont; - - /// Assign the IRQ number from the pci_dev structure - dev->irq = pcidev->irq; - - // Set basic device context - dev->pcidev = pcidev; // PCI device structure - dev->device = &(pcidev->dev); // Device structure - dev->hwFunc = hfunc; // Hardware function pointer - - // Initialize device memory regions - dev->reg = dev->base + AGEN2_OFF; // Register base address - dev->rwBase = dev->base + PHY_OFF; // Read/Write base address - dev->rwSize = (2*USER_SIZE) - PHY_OFF; // Read/Write region size - - // GPU Init - Gpu_Init(dev, GPU_ASYNC_CORE_OFFSET); - - // Manage device reset cycle - dev_info(dev->device, "Init: Setting user reset\n"); - AxiVersion_SetUserReset(dev->base + AVER_OFF, true); // Set user reset - dev_info(dev->device, "Init: Clearing user reset\n"); - AxiVersion_SetUserReset(dev->base + AVER_OFF, false); // Clear user reset - - // Configure DMA based on AXI address width: 128bit desc, = 64-bit address map - if ((readl(dev->reg) & 0x10000) != 0) { - axiWidth = (readl(dev->reg + 0x34) >> 8) & 0xFF; // Extract AXI address width - - // Attempt to set DMA and coherent DMA masks based on AXI width - if (!dma_set_mask(dev->device, DMA_BIT_MASK(axiWidth))) { - dev_info(dev->device, "Init: Using %d-bit DMA mask.\n", axiWidth); - - if (!dma_set_coherent_mask(dev->device, DMA_BIT_MASK(axiWidth))) { - dev_info(dev->device, "Init: Using %d-bit coherent DMA mask.\n", axiWidth); - } else { - dev_err(dev->device, "Init: Failed to set coherent DMA mask.\n"); - probeReturn = -EINVAL; - goto err_post_en; - } - } else { - dev_err(dev->device, "Init: Failed to set DMA mask.\n"); - probeReturn = -EINVAL; - goto err_post_en; - } - } - - // Initialize common DMA functionalities - if (Dma_Init(dev) < 0) { - probeReturn = -ENOMEM; // Indicate memory allocation error - goto err_post_en; - } - - // Log memory mapping information - dev_info(dev->device, "Init: Reg space mapped to 0x%p.\n", dev->reg); - dev_info(dev->device, "Init: User space mapped to 0x%p with size 0x%x.\n", dev->rwBase, dev->rwSize); - dev_info(dev->device, "Init: Top Register = 0x%x\n", readl(dev->reg)); - - // Finalize device probe successfully - gDmaDevCount++; // Increment global device count - return 0; // Success - -err_post_en: - pci_disable_device(pcidev); // Disable PCI device on failure -err_pre_en: - memset(dev, 0, sizeof(*dev)); // Clear out the slot we took over in gDmaDevices - return probeReturn; -} - -/** - * DataGpu_Remove - Clean up resources for a DataGpu device. - * @pcidev: Pointer to the PCI device structure. - * - * This function is called by the PCI subsystem to remove a device (usually on module unload - * or when the device is physically removed from the system). It searches for the device - * within the global DMA devices array, disables the PCI device, cleans up DMA resources, - * and logs the removal. - */ -void DataGpu_Remove(struct pci_dev *pcidev) { - uint32_t x; - struct DmaDevice *dev = NULL; - - /* Log the call to remove the device. */ - pr_info("%s: Remove: Remove called.\n", MOD_NAME); - - /* Search for the device in the global DMA devices array. */ - for (x = 0; x < MAX_DMA_DEVICES; x++) { - if (gDmaDevices[x].baseAddr == pci_resource_start(pcidev, 0)) { - dev = &gDmaDevices[x]; - break; - } - } - - /* If the device is not found, log an error and exit. */ - if (dev == NULL) { - pr_err("%s: Remove: Device Not Found.\n", MOD_NAME); - return; - } - - /* Decrement the global count of DMA devices. */ - gDmaDevCount--; - - /* Clean up DMA resources specific to this device. */ - Dma_Clean(dev); - - /* Disable the PCI device to prevent further access. */ - pci_disable_device(pcidev); - - /* Log the successful removal of the device. */ - pr_info("%s: Remove: Driver is unloaded.\n", MOD_NAME); -} - -/** - * DataGpu_Command - Execute specific commands on a DMA device. - * - * This function handles various commands directed towards DMA devices, specifically - * targeting GPU-related operations, AXI version reading, and other device-specific commands. - * Depending on the command, it delegates the action to the appropriate handler function. - * - * @dev: Pointer to the DMA device on which the command is to be executed. - * @cmd: The command code that specifies the action to be taken. - * @arg: An argument associated with the command, which can be an address, value, or identifier. - * - * Return: Zero on success, negative error code on failure, or positive return values - * specific to the command executed. - */ -int32_t DataGpu_Command(struct DmaDevice *dev, uint32_t cmd, uint64_t arg) { - switch (cmd) { - // GPU Commands - // Handles adding or removing Nvidia memory based on the command specified. - case GPU_Add_Nvidia_Memory: - case GPU_Rem_Nvidia_Memory: - case GPU_Set_Write_Enable: - return Gpu_Command(dev, cmd, arg); - - // AXI Version Read - // Reads the AXI version from a specified offset within the device. - case AVER_Get: - return AxiVersion_Get(dev, dev->base + AVER_OFF, arg); - - // Default handler for other commands not specifically handled above. - // Delegates to a generic AxisG2_Command function for any other commands. - default: - return AxisG2_Command(dev, cmd, arg); - } - - // If the command is not recognized, return an error. - return -1; -} - -/** - * DataGpu_SeqShow - Display device information in the proc file system. - * - * This function is responsible for adding device-specific data to the proc file - * system, allowing users to read device information such as version details and - * other status information via the `/proc` interface. It reads the AXI version - * information from the device and displays it, along with other device-specific - * information. - * - * @s: Pointer to the seq_file structure, used by the kernel to manage sequence files. - * @dev: Pointer to the DmaDevice structure, representing the device whose information - * is to be displayed. - * - * This function does not return a value. - */ -void DataGpu_SeqShow(struct seq_file *s, struct DmaDevice *dev) { - struct AxiVersion aVer; - - /* Read AXI version information from the device. */ - AxiVersion_Read(dev, dev->base + AVER_OFF, &aVer); - - /* Display the AXI version information. */ - AxiVersion_Show(s, dev, &aVer); - - /* Display additional device-specific information. */ - AxisG2_SeqShow(s, dev); - - /* Display DataGPU-specific state information */ - Gpu_Show(s, dev); -} - -/** - * struct hardware_functions - Define hardware-specific operations for DataGpu. - * - * This structure maps hardware operation callbacks specific to the DataGpu device. - * Each field represents a pointer to a function that implements a specific aspect - * of the device's operation, such as initialization, interrupt handling, buffer - * management, and device-specific commands. - * - * @irq: Interrupt handler for the device. - * @init: Initialize the device. - * @clear: Clear the device state or buffers. - * @enable: Enable or disable the device. - * @retRxBuffer: Retrieve a received buffer from the device. - * @sendBuffer: Send a buffer to the device. - * @command: Send a command to the device. - * @seqShow: Show device sequence information (for debugging or status reports). - */ -struct hardware_functions DataGpu_functions = { - .irq = AxisG2_Irq, // Handle interrupts. - .init = AxisG2_Init, // Initialize device hardware. - .clear = AxisG2_Clear, // Clear device state or buffers. - .enable = AxisG2_Enable, // Enable device operations. - .retRxBuffer = AxisG2_RetRxBuffer, // Retrieve received buffer. - .sendBuffer = AxisG2_SendBuffer, // Send buffer to device. - .command = DataGpu_Command, // Issue commands to device. - .seqShow = DataGpu_SeqShow, // Display device sequence info. -}; - -/** - * Module parameters definition and description. - * - * This section declares module parameters which can be passed at module load time. - * It allows for dynamic configuration of the module's behavior without recompilation. - */ - -/* TX buffer count parameter - * Allows setting the number of transmit buffers used by the module. - * This parameter can be modified at module load time. - */ -module_param(cfgTxCount, int, 0); -MODULE_PARM_DESC(cfgTxCount, "TX buffer count: Number of transmit buffers."); - -/* RX buffer count parameter - * Allows setting the number of receive buffers used by the module. - * This parameter can be modified at module load time. - */ -module_param(cfgRxCount, int, 0); -MODULE_PARM_DESC(cfgRxCount, "RX buffer count: Number of receive buffers."); - -/* Rx/TX buffer size parameter - * Allows setting the size of both receive and transmit buffers. - * This parameter can be modified at module load time. - */ -module_param(cfgSize, int, 0); -MODULE_PARM_DESC(cfgSize, "Rx/TX Buffer size: Size of receive and transmit buffers."); - -/* RX buffer mode parameter - * Allows setting the mode of receive buffers. - * This parameter can be modified at module load time. - */ -module_param(cfgMode, int, 0); -MODULE_PARM_DESC(cfgMode, "RX buffer mode: Mode of the receive buffers."); - -/* RX continue enable parameter - * Enables or disables the continuous receive mode. - * This parameter can be modified at module load time. - */ -module_param(cfgCont, int, 0); -MODULE_PARM_DESC(cfgCont, "RX continue enable: Enable/disable continuous receive mode."); - -/* Used to determine the device name formatting - */ -module_param(cfgDevName, int, 0); -MODULE_PARM_DESC(cfgDevName, "Device Name Formating Setting");