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/kmem.c | |
parent | 24f29cbd62e9b2f30aba8f2357084baf6b70fa17 (diff) | |
download | pcitool-8af9de82916ff76129d01ede66fc4406818c525c.tar.gz pcitool-8af9de82916ff76129d01ede66fc4406818c525c.tar.bz2 pcitool-8af9de82916ff76129d01ede66fc4406818c525c.tar.xz pcitool-8af9de82916ff76129d01ede66fc4406818c525c.zip |
Properly perform synchronization of DMA buffers
Diffstat (limited to 'driver/kmem.c')
-rw-r--r-- | driver/kmem.c | 84 |
1 files changed, 51 insertions, 33 deletions
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; } |