diff options
author | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-10-23 02:43:20 +0200 |
---|---|---|
committer | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-10-23 02:43:20 +0200 |
commit | 8af9de82916ff76129d01ede66fc4406818c525c (patch) | |
tree | 3327adb667efa9426b630ba841a16a598c0f9e0c /driver | |
parent | 24f29cbd62e9b2f30aba8f2357084baf6b70fa17 (diff) | |
download | ipecamera-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.h | 2 | ||||
-rw-r--r-- | driver/kmem.c | 84 | ||||
-rw-r--r-- | driver/sysfs.c | 4 |
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 |