159 lines
5.1 KiB
C
Executable File
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;
|
|
}
|