summaryrefslogtreecommitdiffstats
path: root/driver
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-10-23 02:43:20 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-10-23 02:43:20 +0200
commit8af9de82916ff76129d01ede66fc4406818c525c (patch)
tree3327adb667efa9426b630ba841a16a598c0f9e0c /driver
parent24f29cbd62e9b2f30aba8f2357084baf6b70fa17 (diff)
downloadipecamera-8af9de82916ff76129d01ede66fc4406818c525c.tar.gz
ipecamera-8af9de82916ff76129d01ede66fc4406818c525c.tar.bz2
ipecamera-8af9de82916ff76129d01ede66fc4406818c525c.tar.xz
ipecamera-8af9de82916ff76129d01ede66fc4406818c525c.zip
Properly perform synchronization of DMA buffers
Diffstat (limited to 'driver')
-rw-r--r--driver/common.h2
-rw-r--r--driver/kmem.c84
-rw-r--r--driver/sysfs.c4
3 files changed, 55 insertions, 35 deletions
diff --git a/driver/common.h b/driver/common.h
index e6dea5f..eba56d7 100644
--- a/driver/common.h
+++ b/driver/common.h
@@ -11,6 +11,8 @@
/* This list keeps references to the allocated kernel buffers */
typedef struct {
int id;
+ enum dma_data_direction direction;
+
struct list_head list;
dma_addr_t dma_handle;
unsigned long cpua;
diff --git a/driver/kmem.c b/driver/kmem.c
index afe3889..acf1263 100644
--- a/driver/kmem.c
+++ b/driver/kmem.c
@@ -46,19 +46,19 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
kmem_handle->align = kmem_entry->align;
} else {
if (kmem_handle->type != kmem_entry->type) {
- mod_info("Invalid type of reusable kmem_entry\n");
+ mod_info("Invalid type of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->type, kmem_handle->type);
return -EINVAL;
}
- if (kmem_handle->type == PCILIB_KMEM_TYPE_PAGE) {
+ if ((kmem_handle->type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_PAGE) {
kmem_handle->size = kmem_entry->size;
} else if (kmem_handle->size != kmem_entry->size) {
- mod_info("Invalid size of reusable kmem_entry\n");
+ mod_info("Invalid size of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->size, kmem_handle->size);
return -EINVAL;
}
if (kmem_handle->align != kmem_entry->align) {
- mod_info("Invalid alignment of reusable kmem_entry\n");
+ mod_info("Invalid alignment of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->align, kmem_handle->align);
return -EINVAL;
}
@@ -112,6 +112,7 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
kmem_entry->item = kmem_handle->item;
kmem_entry->type = kmem_handle->type;
kmem_entry->align = kmem_handle->align;
+ kmem_entry->direction = PCI_DMA_NONE;
/* Initialize sysfs if possible */
if (pcidriver_sysfs_initialize_kmem(privdata, kmem_entry->id, &(kmem_entry->sysfs_attr)) != 0)
@@ -124,7 +125,7 @@ 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.
*/
- switch (kmem_entry->type) {
+ switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
case PCILIB_KMEM_TYPE_CONSISTENT:
retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) );
break;
@@ -132,13 +133,32 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
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);
+
+ if (retptr) {
+ if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
+ kmem_entry->direction = PCI_DMA_TODEVICE;
+ kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, PAGE_SIZE, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) {
+ free_page((unsigned long)retptr);
+ goto kmem_alloc_mem_fail;
+ }
+ } else if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE) {
+ kmem_entry->direction = PCI_DMA_FROMDEVICE;
+ kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) {
+ free_page((unsigned long)retptr);
+ goto kmem_alloc_mem_fail;
+
+ }
+ }
+ }
+
break;
default:
goto kmem_alloc_mem_fail;
}
+
+
if (retptr == NULL)
goto kmem_alloc_mem_fail;
@@ -316,42 +336,34 @@ 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->direction == PCI_DMA_NONE)
+ return -EINVAL;
- 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:
- pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE );
+ case PCILIB_KMEM_SYNC_TODEVICE:
+ pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
break;
- case PCIDRIVER_DMA_FROMDEVICE:
- pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE );
+ case PCILIB_KMEM_SYNC_FROMDEVICE:
+ pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
break;
- case PCIDRIVER_DMA_BIDIRECTIONAL:
- pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_BIDIRECTIONAL );
- pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_BIDIRECTIONAL );
+ case PCILIB_KMEM_SYNC_BIDIRECTIONAL:
+ pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
+ pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
break;
default:
return -EINVAL; /* wrong direction parameter */
}
#else
switch (kmem_sync->dir) {
- case PCIDRIVER_DMA_TODEVICE:
- pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE );
+ case PCILIB_KMEM_SYNC_TODEVICE:
+ pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
break;
- case PCIDRIVER_DMA_FROMDEVICE:
- pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE );
+ case PCILIB_KMEM_SYNC_FROMDEVICE:
+ pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
break;
- case PCIDRIVER_DMA_BIDIRECTIONAL:
- pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_BIDIRECTIONAL );
+ case PCILIB_KMEM_SYNC_BIDIRECTIONAL:
+ pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
break;
default:
return -EINVAL; /* wrong direction parameter */
@@ -400,12 +412,18 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent
#endif
/* Release DMA memory */
- switch (kmem_entry->type) {
+ switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
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);
+ if (kmem_entry->dma_handle) {
+ if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
+ pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE);
+ } else if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE) {
+ pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE);
+ }
+ }
free_page((unsigned long)kmem_entry->cpua);
break;
}
diff --git a/driver/sysfs.c b/driver/sysfs.c
index b10157b..be6f7d9 100644
--- a/driver/sysfs.c
+++ b/driver/sysfs.c
@@ -102,9 +102,9 @@ static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry)
pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id);
if (entry)
if (entry->size >= 16)
- return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lu\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n data: %8x %8x %8x %8x\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode, *(u32*)(entry->cpua), *(u32*)(entry->cpua + 4), *(u32*)(entry->cpua + 8), *(u32*)(entry->cpua + 12));
+ return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\ndata: %8x %8x %8x %8x\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode, *(u32*)(entry->cpua), *(u32*)(entry->cpua + 4), *(u32*)(entry->cpua + 8), *(u32*)(entry->cpua + 12));
else
- return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lu\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode);
+ return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode);
else
return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id);
#else