From 2e7a7a3534bcf591c0d6c65105b2d845f293112f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 4 Jul 2011 16:21:23 +0200 Subject: North West Logick DMA implementation --- driver/Makefile | 4 +++- driver/base.c | 12 ++++++++++++ driver/common.h | 4 ++++ driver/config.h | 2 +- driver/ioctl.c | 7 ++++++- driver/kmem.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- driver/pciDriver.h | 14 +++++++++----- 7 files changed, 78 insertions(+), 13 deletions(-) (limited to 'driver') diff --git a/driver/Makefile b/driver/Makefile index 9f8918a..9eedc1e 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -6,8 +6,10 @@ KERNELDIR ?= /lib/modules/$(shell uname -r)/build INSTALLDIR ?= /lib/modules/$(shell uname -r)/extra PWD := $(shell pwd) +EXTRA_CFLAGS += -I$(M)/.. + default: - $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + $(MAKE) $(CFLAGS) -C $(KERNELDIR) M=$(PWD) modules install: @mkdir -p $(INSTALLDIR) diff --git a/driver/base.c b/driver/base.c index 581e6d5..2c3ff23 100644 --- a/driver/base.c +++ b/driver/base.c @@ -319,6 +319,17 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi mod_info("Couldn't enable device\n"); goto probe_pcien_fail; } + + /* Bus master & dma */ + if ((id->vendor == PCIE_XILINX_VENDOR_ID)&&(id->device == PCIE_IPECAMERA_DEVICE_ID)) { + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err < 0) { + printk(KERN_ERR "pci_set_dma_mask failed\n"); + goto probe_dma_fail; + } + } /* Set Memory-Write-Invalidate support */ if ((err = pci_set_mwi(pdev)) != 0) @@ -404,6 +415,7 @@ probe_irq_probe_fail: probe_nomem: atomic_dec(&pcidriver_deviceCount); probe_maxdevices_fail: +probe_dma_fail: pci_disable_device(pdev); probe_pcien_fail: return err; diff --git a/driver/common.h b/driver/common.h index 992f0ea..6036b0c 100644 --- a/driver/common.h +++ b/driver/common.h @@ -1,6 +1,8 @@ #ifndef _PCIDRIVER_COMMON_H #define _PCIDRIVER_COMMON_H +#include "pcilib_types.h" + /*************************************************************************/ /* Private data types and structures */ @@ -12,6 +14,8 @@ typedef struct { dma_addr_t dma_handle; unsigned long cpua; unsigned long size; + unsigned long type; + unsigned long use; struct class_device_attribute sysfs_attr; /* initialized when adding the entry */ } pcidriver_kmem_entry_t; diff --git a/driver/config.h b/driver/config.h index c217afd..a2b6946 100644 --- a/driver/config.h +++ b/driver/config.h @@ -3,7 +3,7 @@ /*******************************/ /* Debug messages */ -//#define DEBUG +#define DEBUG /* Enable/disable IRQ handling */ #define ENABLE_IRQ diff --git a/driver/ioctl.c b/driver/ioctl.c index dacf94a..64985e8 100644 --- a/driver/ioctl.c +++ b/driver/ioctl.c @@ -218,7 +218,12 @@ static int ioctl_kmem_sync(pcidriver_privdata_t *privdata, unsigned long arg) int ret; READ_FROM_USER(kmem_sync_t, ksync); - return pcidriver_kmem_sync(privdata, &ksync); + if ((ret = pcidriver_kmem_sync(privdata, &ksync)) != 0) + return ret; + + WRITE_TO_USER(kmem_sync_t, ksync); + + return 0; } /* diff --git a/driver/kmem.c b/driver/kmem.c index 737b74d..95a5487 100644 --- a/driver/kmem.c +++ b/driver/kmem.c @@ -41,7 +41,8 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han /* Initialize the kmem_entry */ kmem_entry->id = atomic_inc_return(&privdata->kmem_count) - 1; - kmem_entry->size = kmem_handle->size; + kmem_entry->use = kmem_handle->use; + kmem_entry->type = kmem_handle->type; kmem_handle->handle_id = kmem_entry->id; /* Initialize sysfs if possible */ @@ -55,9 +56,25 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han * CPU address is used for the mmap (internal to the driver), and * PCI address is the address passed to the DMA Controller in the device. */ - retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) ); + switch (kmem_entry->type) { + case PCILIB_KMEM_TYPE_CONSISTENT: + retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) ); + break; + case PCILIB_KMEM_TYPE_PAGE: + retptr = (void*)__get_free_pages(GFP_KERNEL, get_order(PAGE_SIZE)); + kmem_entry->dma_handle = 0; + kmem_handle->size = PAGE_SIZE; + +// kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, PAGE_SIZE, PCI_DMA_FROMDEVICE); +// printk("%llx %lx\n", kmem_entry->dma_handle, retptr); + break; + default: + goto kmem_alloc_mem_fail; + } if (retptr == NULL) goto kmem_alloc_mem_fail; + + kmem_entry->size = kmem_handle->size; kmem_entry->cpua = (unsigned long)retptr; kmem_handle->pa = (unsigned long)(kmem_entry->dma_handle); @@ -124,6 +141,17 @@ int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync if ((kmem_entry = pcidriver_kmem_find_entry(privdata, &(kmem_sync->handle))) == NULL) return -EINVAL; /* kmem_handle is not valid */ + + if (!kmem_entry->dma_handle) { + mod_info_dbg("Instead of synchronization, we are mapping kmem_entry with id: %d\n", kmem_entry->id); + if (kmem_sync->dir == PCIDRIVER_DMA_TODEVICE) + kmem_entry->dma_handle = pci_map_single(privdata->pdev, (void*)kmem_entry->cpua, kmem_entry->size, PCI_DMA_TODEVICE); + else + kmem_entry->dma_handle = pci_map_single(privdata->pdev, (void*)kmem_entry->cpua, kmem_entry->size, PCI_DMA_FROMDEVICE); + + kmem_sync->handle.pa = kmem_entry->dma_handle; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) switch (kmem_sync->dir) { case PCIDRIVER_DMA_TODEVICE: @@ -197,7 +225,16 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent #endif /* Release DMA memory */ - pci_free_consistent( privdata->pdev, kmem_entry->size, (void *)(kmem_entry->cpua), kmem_entry->dma_handle ); + switch (kmem_entry->type) { + case PCILIB_KMEM_TYPE_CONSISTENT: + pci_free_consistent( privdata->pdev, kmem_entry->size, (void *)(kmem_entry->cpua), kmem_entry->dma_handle ); + break; + case PCILIB_KMEM_TYPE_PAGE: + if (kmem_entry->dma_handle) pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE); + free_page((unsigned long)kmem_entry->cpua); + break; + } + /* Remove the kmem list entry */ spin_lock( &(privdata->kmemlist_lock) ); @@ -226,7 +263,7 @@ pcidriver_kmem_entry_t *pcidriver_kmem_find_entry(pcidriver_privdata_t *privdata list_for_each(ptr, &(privdata->kmem_list)) { entry = list_entry(ptr, pcidriver_kmem_entry_t, list); - if (entry->dma_handle == kmem_handle->pa) { + if (entry->id == kmem_handle->handle_id) { result = entry; break; } @@ -288,6 +325,7 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v /* Check sizes */ vma_size = (vma->vm_end - vma->vm_start); + if ((vma_size != kmem_entry->size) && ((kmem_entry->size < PAGE_SIZE) && (vma_size != PAGE_SIZE))) { mod_info("kem_entry size(%lu) and vma size do not match(%lu)\n", kmem_entry->size, vma_size); @@ -316,6 +354,6 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v mod_info("kmem remap failed: %d (%lx)\n", ret,kmem_entry->cpua); return -EAGAIN; } - + return ret; } diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 98c1301..94c98e7 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -57,6 +57,7 @@ */ #include +#include "pcilib_types.h" /* Identifies the PCI-E Xilinx ML605 */ #define PCIE_XILINX_VENDOR_ID 0x10ee @@ -82,9 +83,9 @@ #define PCIDRIVER_MMAP_KMEM 1 /* Direction of a DMA operation */ -#define PCIDRIVER_DMA_BIDIRECTIONAL 0 -#define PCIDRIVER_DMA_TODEVICE 1 -#define PCIDRIVER_DMA_FROMDEVICE 2 +#define PCIDRIVER_DMA_BIDIRECTIONAL 0 +#define PCIDRIVER_DMA_TODEVICE PCILIB_KMEM_SYNC_TODEVICE +#define PCIDRIVER_DMA_FROMDEVICE PCILIB_KMEM_SYNC_FROMDEVICE /* Possible sizes in a PCI command */ #define PCIDRIVER_PCI_CFG_SZ_BYTE 1 @@ -100,8 +101,11 @@ /* Types */ typedef struct { + unsigned long type; unsigned long pa; unsigned long size; + unsigned long align; + unsigned long use; int handle_id; } kmem_handle_t; @@ -171,8 +175,8 @@ typedef struct { #define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 ) #define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 ) #define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * ) -#define PCIDRIVER_IOC_KMEM_FREE _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * ) -#define PCIDRIVER_IOC_KMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * ) +#define PCIDRIVER_IOC_KMEM_FREE _IOW ( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * ) +#define PCIDRIVER_IOC_KMEM_SYNC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * ) #define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * ) #define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * ) #define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * ) -- cgit v1.2.3