Files
pcie_data_recorder/pcie_driver/drexdma.c
2026-06-19 07:46:17 -05:00

159 lines
5.1 KiB
C
Executable File

#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/dma-mapping.h>
#include "drexdma.h"
// Initial DMA buffers function
int init_dma_buffers(struct drexpcie_device_priv *drexpcie_priv)
{
int buffer_index;
// allocate an array for the buffer pointers (kernel space)
drexpcie_priv->bufPtr = kzalloc(drexpcie_priv->num_bufs*sizeof(void *),GFP_KERNEL);
if (drexpcie_priv->bufPtr == NULL) {
printk("drexpcie[%d]: error, failed to alloc bufPtr memory\n", drexpcie_priv->chnum);
return -ENOMEM;
}
// allocate an array for the dma pointers (physical address)
drexpcie_priv->dmaPtr = kzalloc(drexpcie_priv->num_bufs*sizeof(dma_addr_t),GFP_KERNEL);
if (drexpcie_priv->dmaPtr == NULL) {
printk("drexpcie[%d]: error, failed to alloc dmaPtr memory\n", drexpcie_priv->chnum);
return -ENOMEM;
}
// loop through the total number of desired buffer and attempt to allocate;
// This will populate both the bufPtr and dmaPtr
for (buffer_index = 0; buffer_index < drexpcie_priv->num_bufs; buffer_index++) {
drexpcie_priv->bufPtr[buffer_index] = dma_alloc_coherent(&(drexpcie_priv->driv_priv->pdev->dev), drexpcie_priv->num_bytes, &drexpcie_priv->dmaPtr[buffer_index], GFP_KERNEL);
printk("Allocating Memory: %p, %llX\n",drexpcie_priv->bufPtr[buffer_index],drexpcie_priv->dmaPtr[buffer_index]);
if (drexpcie_priv->bufPtr[buffer_index] == NULL) {
printk("drexpcie[%d]: warning, DMA mem allocation failed at %d buffers\n", drexpcie_priv->chnum, buffer_index);
break;
}
}
drexpcie_priv->valid_bufs = buffer_index;
return 0;
}
// Release (free) DMA buffers function
void release_dma_buffers(struct drexpcie_device_priv *drexpcie_priv)
{
int buffer_index;
if (drexpcie_priv->bufPtr) {
for (buffer_index=0; buffer_index<drexpcie_priv->valid_bufs; buffer_index++) {
if (drexpcie_priv->bufPtr[buffer_index]) {
printk("Freeing Memory: %p, %llX\n",drexpcie_priv->bufPtr[buffer_index],drexpcie_priv->dmaPtr[buffer_index]);
dma_free_coherent(&(drexpcie_priv->driv_priv->pdev->dev), drexpcie_priv->num_bytes , drexpcie_priv->bufPtr[buffer_index], drexpcie_priv->dmaPtr[buffer_index]);
// This is unnecessary, but cleaner
drexpcie_priv->bufPtr[buffer_index] = NULL;
drexpcie_priv->dmaPtr[buffer_index] = (dma_addr_t) NULL;
}
}
kfree(drexpcie_priv->bufPtr);
drexpcie_priv->bufPtr = NULL;
}
if (drexpcie_priv->dmaPtr) {
kfree(drexpcie_priv->dmaPtr);
drexpcie_priv->dmaPtr = NULL;
}
drexpcie_priv->valid_bufs = 0;
}
// Start the DMA function
int dma_init(struct drexpcie_device_priv *drexpcie_priv)
{
int i;
int ret;
uint32_t temp[3];
uint64_t temp64;
// set reset bits
iowrite32(0x00000007, drexpcie_priv->base_mem+DREXDMA_OFFSET_CTRL);
// clears queues if dma_start is called multiple times.
release_dma_buffers(drexpcie_priv);
ret = init_dma_buffers(drexpcie_priv);
if (ret) {
release_dma_buffers(drexpcie_priv);
return ret;
}
// clear reset bits
iowrite32(0x00000000, drexpcie_priv->base_mem+DREXDMA_OFFSET_CTRL);
// writes buffer to the available FIFO
printk("drexpcie[%d]: writing %d buffers to FIFO\n", drexpcie_priv->chnum, drexpcie_priv->valid_bufs );
for (i = 0; i < drexpcie_priv->valid_bufs; i++) {
temp64 = drexpcie_priv->dmaPtr[i];
temp[0] = (((drexpcie_priv->num_bytes) & 0x7FFFFF) << 9);
temp[0] |= (((i) & 0x000001FF));
temp[1] = temp64 & 0xFFFFFFFF;
temp[2] = (temp64 >> 32) & 0x000000FF;
printk("drexpcie[%d]: writing %x %x %x to FIFO\n", drexpcie_priv->chnum, temp[2],temp[1],temp[0]);
iowrite32(temp[0], drexpcie_priv->base_mem+DREXDMA_OFFSET_FIFO);
iowrite32(temp[1], drexpcie_priv->base_mem+DREXDMA_OFFSET_FIFO+4);
iowrite32(temp[2], drexpcie_priv->base_mem+DREXDMA_OFFSET_FIFO+8);
}
// Enable Loop Mode
printk("drexpcie[%d]: enabling loop mode\n", drexpcie_priv->chnum);
iowrite32(1, drexpcie_priv->base_mem+DREXDMA_OFFSET_CTRL+4);
// Enable DMA Engine
// iowrite32(0x00000100, drexpcie_privDREXDMA_OFFSET_CTRL);
return 0;
}
int dma_clear(struct drexpcie_device_priv *drexpcie_priv)
{
// set reset bits
iowrite32(0x00000007, drexpcie_priv->base_mem+DREXDMA_OFFSET_CTRL);
// Disable Loop Mode
iowrite32(0, drexpcie_priv->base_mem+DREXDMA_OFFSET_CTRL+4);
release_dma_buffers(drexpcie_priv);
return 0;
}
int dma_start(struct drexpcie_device_priv *drexpcie_priv)
{
// Enable DMA Engine
iowrite32(0x00000100, drexpcie_priv->base_mem+DREXDMA_OFFSET_CTRL);
return 0;
}
int dma_stop(struct drexpcie_device_priv *drexpcie_priv)
{
// Disable DMA Engine
iowrite32(0x00000000, drexpcie_priv->base_mem+DREXDMA_OFFSET_CTRL);
return 0;
}