Commit 8a5068c7 authored by Jens Korinth's avatar Jens Korinth

Backport new VC709 driver to Tapasco

parent 4f9d515b
......@@ -6,7 +6,7 @@ obj-m := ffLink.o
# composition of files needed to compile
# one can exchange dual_dma_ctrl with cdma_dma_ctrl, when dma engine from Xilinx is used
ffLink-objs := pcie_device.o dual_dma_ctrl.o char_device_dma.o char_device_user.o ffLink_driver.o
ffLink-objs := pcie_device.o blue_dma_ctrl.o char_device_dma.o char_device_user.o ffLink_driver.o dual_dma_ctrl.o dma_ctrl.o
# Path to kernel headers for compilation (path to home can be specific to os)
LNX=$(shell uname -r)
......
//
// Copyright (C) 2014 David de la Chevallerie, TU Darmstadt
// Copyright (C) 2017 Jaco A. Hofmann, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
......@@ -17,8 +17,8 @@
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
/**
* @file cdma_dma_ctrl.c
* @brief Implementation of Xilinx dma engine specific code
* @file dual_dma_ctrl.c
* @brief Implementation of custom dma engine specific code
Strips the layout of the dma-registers and setup stuff to start a dma transfer
in addition calls to acknowledge the interrupt in hw is given
* */
......@@ -30,21 +30,13 @@
/******************************************************************************/
/* Register Map and commands */
#define REG_CDMACR 0x00 /* slv_reg0 = CDMA Control */
#define REG_CDMASR 0x04 /* slv_reg1 = CDMA Status */
#define REG_CURDESC_PNTR 0x08 /* slv_reg2 = Current Descriptor Pointer */
#define REG_CURDESC_PNTR_MSB 0x0C /* slv_reg3 = Current Descriptor Pointer (MSB 32 bits) */
#define REG_TAILDESC_PNTR 0x10 /* slv_reg4 = Tail Descriptor Pointer */
#define REG_TAILDESC_PNTR_MSB 0x14 /* slv_reg5 = Tail Descriptor Pointer (MSB 32 bits) */
#define REG_SA 0x18 /* slv_reg6 = Source Address */
#define REG_SA_MSB 0x1C /* slv_reg7 = Source Address (MSB 32 bits) */
#define REG_DA 0x20 /* slv_reg8 = Destination Address */
#define REG_DA_MSB 0x24 /* slv_reg9 = Destination Address (MSB 32 bits) */
#define REG_BTT 0x28 /* slv_regA = Bytes to Transfer */
#define REG_HOST_ADDR 0x00 /* slv_reg0 = PCIe addr */
#define REG_FPGA_ADDR 0x08 /* slv_reg1 = FPGA addr */
#define REG_BTT 0x10 /* slv_reg2 = bytes to transfer */
#define REG_CMD 0x20 /* slv_reg3 = CMD */
#define CMD_IRQ_EN 0x00001000 /* enables interrupt for transfers in control register */
#define CMD_ACK 0x00001000 /* acknowledge data transfer to toggle interrupt in status register */
#define PCIE_OFF 0x00000008 /* offset to address pcie core */
#define CMD_READ 0x10001000 /* from m64 fpga memory to m64 host memory */
#define CMD_WRITE 0x10000001 /* from m64 host memory to m64 fpga memory */
/* mutex to sequentialize access to dma registers */
//static DEFINE_MUTEX(dma_regs_mutex);
......@@ -52,73 +44,14 @@
/******************************************************************************/
/* functions for irq-handling */
/**
* @brief Acknowledge interrupt in hardware and wake up corresponding process
* @param i minor node corresponding to this irq
* @return none
* */
void ack_irq(int i)
{
fflink_info("Handle device number %d\n", i);
/* ack interrupt */
pcie_writel(CMD_ACK, get_dev_addr(i) + REG_CDMASR);
/* Set priv data for more minor nodes accordingly */
wake_up_queue(i);
}
/**
* @brief Interrupt handler for dma engine 0
* @param irq Interrupt number of calling line
* @param dev_id magic number for interrupt sharing (not needed)
* @return Tells OS, that irq is handled properly
* */
irqreturn_t intr_handler_dma_0(int irq, void * dev_id)
{
fflink_info("Interrupt called with irq %d\n", irq);
ack_irq(0);
return IRQ_HANDLED;
}
/**
* @brief Interrupt handler for dma engine 1
* @param irq Interrupt number of calling line
* @param dev_id magic number for interrupt sharing (not needed)
* @return Tells OS, that irq is handled properly
* */
irqreturn_t intr_handler_dma_1(int irq, void * dev_id)
irqreturn_t blue_dma_intr_handler(int irq, void * dev_id)
{
fflink_info("Interrupt called with irq %d\n", irq);
ack_irq(1);
return IRQ_HANDLED;
}
/**
* @brief Interrupt handler for dma engine 2
* @param irq Interrupt number of calling line
* @param dev_id magic number for interrupt sharing (not needed)
* @return Tells OS, that irq is handled properly
* */
irqreturn_t intr_handler_dma_2(int irq, void * dev_id)
{
fflink_info("Interrupt called with irq %d\n", irq);
ack_irq(2);
return IRQ_HANDLED;
}
/**
* @brief Interrupt handler for dma engine 3
* @param irq Interrupt number of calling line
* @param dev_id magic number for interrupt sharing (not needed)
* @return Tells OS, that irq is handled properly
* */
irqreturn_t intr_handler_dma_3(int irq, void * dev_id)
{
fflink_info("Interrupt called with irq %d\n", irq);
ack_irq(3);
return IRQ_HANDLED;
}
......@@ -132,24 +65,22 @@ irqreturn_t intr_handler_dma_3(int irq, void * dev_id)
* @param device_base_addr Address of dma engine registers
* @return none
* */
void transmit_from_device(void * device_buffer, dma_addr_t host_handle, int btt, void * device_base_addr)
void blue_dma_transmit_from_device(void * device_buffer, dma_addr_t host_handle, int btt, void * device_base_addr)
{
fflink_info("dev_buf %lX dma_handle %lX \nsize %d dev_base %lX\n", (unsigned long) device_buffer, (unsigned long) host_handle, btt, (unsigned long) device_base_addr);
//if(mutex_lock_interruptible(&dma_regs_mutex))
// fflink_warn("got killed while aquiring the mutex\n");
/* activate interrupts */
pcie_writel(CMD_IRQ_EN, device_base_addr + REG_CDMACR);
/* SA */
pcie_writel((unsigned long) device_buffer, device_base_addr + REG_SA);
pcie_writel(0, device_base_addr + REG_SA_MSB);
pcie_writel((unsigned long)device_buffer, device_base_addr + REG_FPGA_ADDR);
/* DA */
pcie_writel(host_handle, device_base_addr + REG_DA);
pcie_writel(PCIE_OFF, device_base_addr + REG_DA_MSB);
pcie_writel(host_handle, device_base_addr + REG_HOST_ADDR);
/* btt */
pcie_writel(btt, device_base_addr + REG_BTT);
/* presvious data have to be written first */
wmb();
/* btt and start */
pcie_writel(btt, device_base_addr + REG_BTT);
/* start cmd */
pcie_writel(CMD_READ, device_base_addr + REG_CMD);
//mutex_unlock(&dma_regs_mutex);
}
......@@ -162,24 +93,22 @@ void transmit_from_device(void * device_buffer, dma_addr_t host_handle, int btt,
* @param device_base_addr Address of dma engine registers
* @return none
* */
void transmit_to_device(void * device_buffer, dma_addr_t host_handle, int btt, void * device_base_addr)
void blue_dma_transmit_to_device(void * device_buffer, dma_addr_t host_handle, int btt, void * device_base_addr)
{
fflink_info("dev_buf %lX dma_handle %lX \nsize %d dev_base %lX\n", (unsigned long) device_buffer, (unsigned long) host_handle, btt, (unsigned long) device_base_addr);
//if(mutex_lock_interruptible(&dma_regs_mutex))
// fflink_warn("got killed while aquiring the mutex\n");
/* activate interrupts */
pcie_writel(CMD_IRQ_EN, device_base_addr + REG_CDMACR);
/* SA */
pcie_writel(host_handle, device_base_addr + REG_SA);
pcie_writel(PCIE_OFF, device_base_addr + REG_SA_MSB);
pcie_writel(host_handle, device_base_addr + REG_HOST_ADDR);
/* DA */
pcie_writel((unsigned long) device_buffer, device_base_addr + REG_DA);
pcie_writel(0, device_base_addr + REG_DA_MSB);
pcie_writel((unsigned long)device_buffer, device_base_addr + REG_FPGA_ADDR);
/* btt */
pcie_writel(btt, device_base_addr + REG_BTT);
/* presvious data have to be written first */
wmb();
/* btt and start */
pcie_writel(btt, device_base_addr + REG_BTT);
/* start cmd */
pcie_writel(CMD_WRITE, device_base_addr + REG_CMD);
//mutex_unlock(&dma_regs_mutex);
}
......
//
// Copyright (C) 2014 David de la Chevallerie, TU Darmstadt
// Copyright (C) 2017 Jaco A. Hofmann, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
......@@ -39,12 +40,11 @@ static struct file_operations dma_fops = {
.release = dma_close,
.unlocked_ioctl = dma_ioctl,
.read = dma_read,
.write = dma_write,
.mmap = dma_mmap
.write = dma_write
};
/* private data used to hold additional information throughout multiple system calls */
static struct priv_data_struct priv_data[FFLINK_DMA_NODES];
static struct priv_data_struct priv_data;
/* char device structure basically for dev_t and fops */
static struct cdev char_dma_cdev;
......@@ -53,6 +53,9 @@ static dev_t char_dma_dev_t;
/* device class entry for sysfs */
struct class *char_dma_class;
static int device_opened = 0;
static DEFINE_SPINLOCK(device_open_close_mutex);
/******************************************************************************/
/* helper functions used by sys-calls */
......@@ -89,7 +92,7 @@ static void transmit_to_user(void * user_buffer, void * kvirt_buffer, dma_addr_t
static void transmit_from_user(void * user_buffer, void * kvirt_buffer, dma_addr_t dma_handle, int btt)
{
int copy_count;
fflink_info("user_buf %lX kvirt_buf %lX \nsize %d dma_handle %lX\n", (unsigned long) user_buffer, (unsigned long) kvirt_buffer, btt, (unsigned long) dma_handle);
fflink_info("user_buf %lX kvirt_buf %lX \nsize %d dma_handle %lX\n", (unsigned long) user_buffer, (unsigned long) kvirt_buffer, dma_cache_fit(btt), (unsigned long) dma_handle);
dma_sync_single_for_cpu(&get_pcie_dev()->dev, dma_handle, dma_cache_fit(btt), PCI_DMA_TODEVICE);
// copy data from user
......@@ -100,20 +103,6 @@ static void transmit_from_user(void * user_buffer, void * kvirt_buffer, dma_addr
dma_sync_single_for_device(&get_pcie_dev()->dev, dma_handle, dma_cache_fit(btt), PCI_DMA_TODEVICE);
}
/**
* @brief Exchanges data between both pointers
* @param a Pointer to first date
* @param b Pointer to second date
* @return none
* */
static void switch_index(unsigned int * a, unsigned int * b)
{
unsigned int tmp = *a;
*a = *b;
*b = tmp;
}
/**
* @brief Ensures that return value is always >= btt and multiple of cache_line_size
* to invalidate/flush only complete cache lines
......@@ -122,41 +111,10 @@ static void switch_index(unsigned int * a, unsigned int * b)
* */
static unsigned int dma_cache_fit(unsigned int btt)
{
if((btt & (priv_data[0].cache_lsize -1)) > 0)
return (btt & priv_data[0].cache_mask) + priv_data[0].cache_lsize;
if((btt & (priv_data.cache_lsize -1)) > 0)
return (btt & priv_data.cache_mask) + priv_data.cache_lsize;
else
return btt & priv_data[0].cache_mask;
}
/**
* @brief Determines the size of each transfer, when using double_buffering
* @param count Total number of bytes to transfer
* @return Byte size for one transfer
* */
static unsigned int calc_transfer_size(int count)
{
if(count > DOUBLE_BUFFER_LIMIT && count <= 2*BUFFER_SIZE_USED)
return count/2;
else if(count <= DOUBLE_BUFFER_LIMIT)
return count;
else
return BUFFER_SIZE_USED;
}
/**
* @brief Determines the kernel virtual addresses of all buffers
* @param p Priv_data for corresponding minor node
* @return none
* */
static void dma_page_to_virt(struct priv_data_struct * p)
{
int i;
for(i = 0; i < PBUF_SIZE; i++) {
p->kvirt_pbuf_h2l[i] = page_address(p->pbuf_h2l[i]);
p->kvirt_pbuf_l2h[i] = page_address(p->pbuf_l2h[i]);
}
return btt & priv_data.cache_mask;
}
/**
......@@ -168,37 +126,24 @@ static void dma_page_to_virt(struct priv_data_struct * p)
* @param direction Whether writeable or readable
* @return Zero, if all buffers could be allocated and mapped
* */
static int dma_alloc_pbufs(struct page * p[], dma_addr_t handle[], gfp_t zone, int direction)
static int dma_alloc_pbufs(void** p, dma_addr_t *handle, gfp_t zone, int direction)
{
int i, dma_err, err = 0;
void *page_ptr;
fflink_notice("Allocate %d tuple of 2^%d Pages or %lu Byte\n or %lu MByte with Bit-Mask %llX in direction %d (1=H2L 2=L2H)\n",
PBUF_SIZE, BUFFER_ORDER, BUFFER_SIZE, (BUFFER_SIZE/(1024*1024)), DMA_BIT_MASK(DMA_MAX_BIT), direction);
for(i = 0; i < PBUF_SIZE; i++) {
p[i] = 0;
handle[i] = 0;
if(IS_ERR(p[i] = alloc_pages(zone, BUFFER_ORDER))) {
fflink_warn("Cannot allocate 2^%d Pages in iteration %d\n", BUFFER_ORDER, i);
err = -ENOMEM;
} else {
page_ptr = page_address(p[i]);
handle[i] = pci_map_single(get_pcie_dev(), page_ptr, BUFFER_SIZE, direction);
fflink_info("PCI-Mapping Address (Handle map_single): %llX\n", (unsigned long long int) handle[i]);
}
}
dma_err = pci_dma_mapping_error(get_pcie_dev(), handle[i]);
if(dma_err) {
fflink_warn("pci_map mapping error in iteration %d\n", i);
int err = 0;
*p = kmalloc(BUFFER_SIZE, zone);
if(*p) {
memset(*p, 0, BUFFER_SIZE);
*handle = dma_map_single(&get_pcie_dev()->dev, *p, BUFFER_SIZE, direction);
if(dma_mapping_error(&get_pcie_dev()->dev, *handle)) {
fflink_warn("DMA Mapping error\n");
err = -EFAULT;
handle[i] = 0;
}
} else {
fflink_warn("Couldn't retrieve enough memory\n");
err = -EFAULT;
}
return err;
}
}
/**
* @brief Free kernel buffers
......@@ -207,23 +152,13 @@ static int dma_alloc_pbufs(struct page * p[], dma_addr_t handle[], gfp_t zone, i
* @param direction Whether writeable or readable
* @return none
* */
static void dma_free_pbufs(struct page * p[], dma_addr_t handle[], int direction)
static void dma_free_pbufs(void *p, dma_addr_t handle, int direction)
{
int i;
for(i = 0; i < PBUF_SIZE; i++) {
if(handle[i]) {
//fflink_driver_info("Unmap pci-mapping in iteration %d\n", i);
pci_unmap_single(get_pcie_dev(), handle[i], BUFFER_SIZE, direction);
} else {
fflink_notice("No pci-mapping in iteration %d\n", i);
}
if(p[i]) {
//fflink_info("Free 2^%d Pages at %llX\n", order, (unsigned long long) p[i]);
__free_pages(p[i], BUFFER_ORDER);
} else {
fflink_notice("No Pages in iteration %d\n", i);
}
if(handle) {
dma_unmap_single(&get_pcie_dev()->dev, handle, BUFFER_SIZE, direction);
}
if(p) {
kfree(p);
}
}
......@@ -233,52 +168,30 @@ static void dma_free_pbufs(struct page * p[], dma_addr_t handle[], int direction
* @param node Minor number
* @return none
* */
static void dma_init_pdata(struct priv_data_struct * p, int node)
static void dma_init_pdata(struct priv_data_struct * p)
{
/* cache size and mask needed for alignemt */
p->cache_lsize = cache_line_size();
p->cache_mask = ~(cache_line_size() -1);
p->dma_handle_h2l = 0;
p->dma_handle_l2h = 0;
p->kvirt_h2l = 0;
p->kvirt_l2h = 0;
p->minor = node;
p->ctrl_base_addr = (void *) AXI_CTRL_BASE_ADDR;
/* init control structures for synchron sys-calls */
mutex_init(&p->rw_mutex);
init_waitqueue_head(&p->rw_wait_queue);
p->condition_rw = false;
mutex_init(&p->mmap_rbuf_mutex);
mutex_init(&p->mmap_wbuf_mutex);
/* additional information for sys-calls depending on minor number*/
switch(node) {
case 0:
p->mem_addr_h2l = (void *) RAM_BASE_ADDR_0;
p->mem_addr_l2h = (void *) RAM_BASE_ADDR_0;
p->device_base_addr = (void *) DMA_BASE_ADDR_0;
break;
case 1:
p->mem_addr_h2l = (void *) RAM_BASE_ADDR_1;
p->mem_addr_l2h = (void *) RAM_BASE_ADDR_1;
p->device_base_addr = (void *) DMA_BASE_ADDR_1;
break;
case 2:
p->mem_addr_h2l = (void *) RAM_BASE_ADDR_2;
p->mem_addr_l2h = (void *) RAM_BASE_ADDR_2;
p->device_base_addr = (void *) DMA_BASE_ADDR_2;
break;
case 3:
p->mem_addr_h2l = (void *) RAM_BASE_ADDR_3;
p->mem_addr_l2h = (void *) RAM_BASE_ADDR_3;
p->device_base_addr = (void *) DMA_BASE_ADDR_3;
break;
default:
fflink_warn("wrong minor node opened %d\n", node);
break;
}
p->mem_addr_h2l = (void *) RAM_BASE_ADDR_0;
p->mem_addr_l2h = (void *) RAM_BASE_ADDR_0;
p->device_base_addr = (void *) DMA_BASE_ADDR_0;
}
/******************************************************************************/
/**
......@@ -291,60 +204,7 @@ static void dma_init_pdata(struct priv_data_struct * p, int node)
* */
static inline int read_device(int count, char __user *buf, void * mem_addr, struct priv_data_struct *p)
{
if(FFLINK_DOUBLE_BUFFERING == 1)
return read_with_double(count, buf, mem_addr, p);
else
return read_with_bounce(count, buf, mem_addr, p);
}
/**
* @brief Double-buffering implementation to transfer data from FPGA to Main memory
* @param count Bytes to be transferred
* @param buf Pointer to user space buffer
* @param mem_addr Hardware address on the FPGA
* @param p Pointer to priv_data of associated minor node, needed for kernel buffers and sleeping
* @return Zero, if transfer was successful, error code otherwise
* */
static int read_with_double(int count, char __user *buf, void * mem_addr, struct priv_data_struct *p)
{
int current_count = count;
unsigned int copy_size = calc_transfer_size(count), tic = 1, toc = 2;
fflink_notice("outstanding %d bytes - \n\t\t user addr %lX - mem addr %lx - with copy_size: %u\n", current_count, (unsigned long) buf, (unsigned long) mem_addr, copy_size);
transmit_from_device(mem_addr, p->dma_handle_l2h[tic], copy_size, p->device_base_addr);
current_count -= copy_size;
mem_addr += copy_size;
while(current_count > 0) {
fflink_info("outstanding %d bytes - \n\t\t user addr %lX - mem addr %lx - tic %d - toc %d\n", current_count, (unsigned long) buf, (unsigned long) mem_addr, tic, toc);
if(wait_event_interruptible(p->rw_wait_queue, p->condition_rw == true)) {
fflink_warn("got killed while hanging in waiting queue\n");
return -EACCES;
}
p->condition_rw = false;
if(current_count <= BUFFER_SIZE_USED) {
transmit_from_device(mem_addr, p->dma_handle_l2h[toc], current_count, p->device_base_addr);
transmit_to_user(buf, p->kvirt_pbuf_l2h[tic], p->dma_handle_l2h[tic], current_count);
} else {
transmit_from_device(mem_addr, p->dma_handle_l2h[toc], BUFFER_SIZE_USED, p->device_base_addr);
transmit_to_user(buf, p->kvirt_pbuf_l2h[tic], p->dma_handle_l2h[tic], BUFFER_SIZE_USED);
}
current_count -= copy_size;
buf += copy_size;
mem_addr += copy_size;
switch_index(&tic, &toc);
}
if(wait_event_interruptible(p->rw_wait_queue, p->condition_rw == true)) {
fflink_warn("got killed while hanging in waiting queue\n");
return -EACCES;
}
p->condition_rw = false;
transmit_to_user(buf, p->kvirt_pbuf_l2h[tic], p->dma_handle_l2h[tic], copy_size);
return 0;
return read_with_bounce(count, buf, mem_addr, p);
}
/**
......@@ -368,13 +228,13 @@ static int read_with_bounce(int count, char __user *buf, void * mem_addr, struct
else
copy_size = BUFFER_SIZE;
transmit_from_device(mem_addr, p->dma_handle_l2h[1], copy_size, p->device_base_addr);
transmit_from_device(mem_addr, p->dma_handle_l2h, copy_size, p->device_base_addr);
if(wait_event_interruptible(p->rw_wait_queue, p->condition_rw == true)) {
fflink_warn("got killed while hanging in waiting queue\n");
return -EACCES;
}
p->condition_rw = false;
transmit_to_user(buf, p->kvirt_pbuf_l2h[1], p->dma_handle_l2h[1], copy_size);
transmit_to_user(buf, p->kvirt_l2h, p->dma_handle_l2h, copy_size);
buf += BUFFER_SIZE;
mem_addr += BUFFER_SIZE;
......@@ -395,60 +255,7 @@ static int read_with_bounce(int count, char __user *buf, void * mem_addr, struct
* */
static inline int write_device(int count, const char __user *buf, void * mem_addr, struct priv_data_struct *p)
{
if(FFLINK_DOUBLE_BUFFERING == 1)
return write_with_double(count, buf, mem_addr, p);
else
return write_with_bounce(count, buf, mem_addr, p);
}
/**
* @brief Double-buffering implementation to transfer data from Main to FPGA memory
* @param count Bytes to be transferred
* @param buf Pointer to user space buffer
* @param mem_addr Hardware address on the FPGA
* @param p Pointer to priv_data of associated minor node, needed for kernel buffers and sleeping
* @return Zero, if transfer was successful, error code otherwise
* */
static int write_with_double(int count, const char __user *buf, void * mem_addr, struct priv_data_struct *p)
{
int current_count = count;
unsigned int copy_size = calc_transfer_size(count), tic = 1, toc = 2;
fflink_notice("outstanding %d bytes - \n\t\t user addr %lX - mem addr %lx - with copy_size: %u\n", current_count, (unsigned long) buf, (unsigned long) mem_addr, copy_size);
transmit_from_user((void *) buf, p->kvirt_pbuf_h2l[tic], p->dma_handle_h2l[tic], copy_size);
current_count -= copy_size;
buf += copy_size;
while(current_count > 0) {
fflink_info("outstanding %d bytes - \n\t\t user addr %lX - mem addr %lx\n", current_count, (unsigned long) buf, (unsigned long) p->mem_addr_h2l);
if(current_count <= BUFFER_SIZE_USED) {
transmit_to_device(mem_addr, p->dma_handle_h2l[tic], current_count, p->device_base_addr);
transmit_from_user((void *) buf, p->kvirt_pbuf_h2l[toc], p->dma_handle_h2l[toc], current_count);
} else {
transmit_to_device(mem_addr, p->dma_handle_h2l[tic], BUFFER_SIZE_USED , p->device_base_addr);
transmit_from_user((void *) buf, p->kvirt_pbuf_h2l[toc], p->dma_handle_h2l[toc], BUFFER_SIZE_USED);
}
current_count -= copy_size;
buf += copy_size;
mem_addr += copy_size;
switch_index(&tic, &toc);
if(wait_event_interruptible(p->rw_wait_queue, p->condition_rw == true)) {
fflink_warn("got killed while hanging in waiting queue\n");
return -EACCES;
}
p->condition_rw = false;
}
transmit_to_device(mem_addr, p->dma_handle_h2l[tic], copy_size , p->device_base_addr);
if(wait_event_interruptible(p->rw_wait_queue, p->condition_rw == true)) {
fflink_warn("got killed while hanging in waiting queue\n");
return -EACCES;
}
p->condition_rw = false;
return 0;
return write_with_bounce(count, buf, mem_addr, p);
}
/**
......@@ -467,11 +274,11 @@ static int write_with_bounce(int count, const char __user *buf, void * mem_addr,
while(current_count > 0) {
fflink_info("outstanding %d bytes - \n\t\t user addr %lX - mem addr %lx\n", current_count, (unsigned long) buf, (unsigned long) mem_addr);
if(current_count <= BUFFER_SIZE) {
transmit_from_user((void *) buf, p->kvirt_pbuf_h2l[1], p->dma_handle_h2l[1], current_count);
transmit_to_device(mem_addr, p->dma_handle_h2l[1], current_count, p->device_base_addr);
transmit_from_user((void *) buf, p->kvirt_h2l, p->dma_handle_h2l, current_count);
transmit_to_device(mem_addr, p->dma_handle_h2l, current_count, p->device_base_addr);
} else {
transmit_from_user((void *) buf, p->kvirt_pbuf_h2l[1], p->dma_handle_h2l[1], BUFFER_SIZE);
transmit_to_device(mem_addr, p->dma_handle_h2l[1], BUFFER_SIZE , p->device_base_addr);
transmit_from_user((void *) buf, p->kvirt_h2l, p->dma_handle_h2l, BUFFER_SIZE);
transmit_to_device(mem_addr, p->dma_handle_h2l, BUFFER_SIZE , p->device_base_addr);
}
buf += BUFFER_SIZE;
mem_addr += BUFFER_SIZE;
......@@ -486,51 +293,72 @@ static int write_with_bounce(int count, const char __user *buf, void * mem_addr,
return 0;
}
/******************************************************************************/
/* functions for user-space interaction */
static int dma_initialize(void) {
int err_1 = 0, err_2 = 0, err_return = 0;
gfp_t zone = GFP_DMA32;
/**
* @brief When minor node is opened, kernel buffers will be allocated,
performs dma-mappings and registeres these in filp for further calls
* @param inode Representation of node in /dev, used to get major-/minor-number
* @param filp Mostly used to allocate private data for consecutive calls
* @return Zero, if char-device could be opened, error code otherwise
* */
static int dma_open(struct inode *inode, struct file *filp)
{
int err_1 = 0, err_2 = 0;
fflink_notice("Called for device (<%d,%d>)\n", imajor(inode), iminor(inode));
fflink_notice("Initializing private data");
/* currently maximal four engines are supported - see switch case in dma_init */
if(iminor(inode) < FFLINK_DMA_NODES && iminor(inode) >= 0 && iminor(inode) < 4)
dma_init_pdata(&priv_data[iminor(inode)], iminor(inode));
else
return -ENODEV;