]> Pileus Git - ~andy/linux/blobdiff - drivers/firewire/core-iso.c
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[~andy/linux] / drivers / firewire / core-iso.c
index d1565828ae2c0104535ec008a16b70d21973f38f..8382e27e9a271877c98d24ff6268f9d578738b47 100644 (file)
  * Isochronous DMA context management
  */
 
-int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
-                      int page_count, enum dma_data_direction direction)
+int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count)
 {
-       int i, j;
-       dma_addr_t address;
-
-       buffer->page_count = page_count;
-       buffer->direction = direction;
+       int i;
 
+       buffer->page_count = 0;
+       buffer->page_count_mapped = 0;
        buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]),
                                GFP_KERNEL);
        if (buffer->pages == NULL)
-               goto out;
+               return -ENOMEM;
 
-       for (i = 0; i < buffer->page_count; i++) {
+       for (i = 0; i < page_count; i++) {
                buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
                if (buffer->pages[i] == NULL)
-                       goto out_pages;
+                       break;
+       }
+       buffer->page_count = i;
+       if (i < page_count) {
+               fw_iso_buffer_destroy(buffer, NULL);
+               return -ENOMEM;
+       }
 
+       return 0;
+}
+
+int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
+                         enum dma_data_direction direction)
+{
+       dma_addr_t address;
+       int i;
+
+       buffer->direction = direction;
+
+       for (i = 0; i < buffer->page_count; i++) {
                address = dma_map_page(card->device, buffer->pages[i],
                                       0, PAGE_SIZE, direction);
-               if (dma_mapping_error(card->device, address)) {
-                       __free_page(buffer->pages[i]);
-                       goto out_pages;
-               }
+               if (dma_mapping_error(card->device, address))
+                       break;
+
                set_page_private(buffer->pages[i], address);
        }
+       buffer->page_count_mapped = i;
+       if (i < buffer->page_count)
+               return -ENOMEM;
 
        return 0;
+}
 
- out_pages:
-       for (j = 0; j < i; j++) {
-               address = page_private(buffer->pages[j]);
-               dma_unmap_page(card->device, address,
-                              PAGE_SIZE, direction);
-               __free_page(buffer->pages[j]);
-       }
-       kfree(buffer->pages);
- out:
-       buffer->pages = NULL;
+int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
+                      int page_count, enum dma_data_direction direction)
+{
+       int ret;
+
+       ret = fw_iso_buffer_alloc(buffer, page_count);
+       if (ret < 0)
+               return ret;
+
+       ret = fw_iso_buffer_map_dma(buffer, card, direction);
+       if (ret < 0)
+               fw_iso_buffer_destroy(buffer, card);
 
-       return -ENOMEM;
+       return ret;
 }
 EXPORT_SYMBOL(fw_iso_buffer_init);
 
-int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
+int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
+                         struct vm_area_struct *vma)
 {
        unsigned long uaddr;
        int i, err;
@@ -107,15 +128,18 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
        int i;
        dma_addr_t address;
 
-       for (i = 0; i < buffer->page_count; i++) {
+       for (i = 0; i < buffer->page_count_mapped; i++) {
                address = page_private(buffer->pages[i]);
                dma_unmap_page(card->device, address,
                               PAGE_SIZE, buffer->direction);
-               __free_page(buffer->pages[i]);
        }
+       for (i = 0; i < buffer->page_count; i++)
+               __free_page(buffer->pages[i]);
 
        kfree(buffer->pages);
        buffer->pages = NULL;
+       buffer->page_count = 0;
+       buffer->page_count_mapped = 0;
 }
 EXPORT_SYMBOL(fw_iso_buffer_destroy);