diff options
Diffstat (limited to 'drivers/firewire/fw-iso.c')
-rw-r--r-- | drivers/firewire/fw-iso.c | 118 |
1 files changed, 66 insertions, 52 deletions
diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c index 6481e3df2c93..4e7ba8672929 100644 --- a/drivers/firewire/fw-iso.c +++ b/drivers/firewire/fw-iso.c | |||
@@ -28,68 +28,88 @@ | |||
28 | #include "fw-topology.h" | 28 | #include "fw-topology.h" |
29 | #include "fw-device.h" | 29 | #include "fw-device.h" |
30 | 30 | ||
31 | static int | 31 | int |
32 | setup_iso_buffer(struct fw_iso_context *ctx, size_t size, | 32 | fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, |
33 | enum dma_data_direction direction) | 33 | int page_count, enum dma_data_direction direction) |
34 | { | 34 | { |
35 | struct page *page; | 35 | int i, j, retval = -ENOMEM; |
36 | int i, j; | 36 | dma_addr_t address; |
37 | void *p; | 37 | |
38 | 38 | buffer->page_count = page_count; | |
39 | ctx->buffer_size = PAGE_ALIGN(size); | 39 | buffer->direction = direction; |
40 | if (size == 0) | 40 | |
41 | return 0; | 41 | buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]), |
42 | 42 | GFP_KERNEL); | |
43 | ctx->buffer = vmalloc_32_user(ctx->buffer_size); | 43 | if (buffer->pages == NULL) |
44 | if (ctx->buffer == NULL) | 44 | goto out; |
45 | goto fail_buffer_alloc; | 45 | |
46 | 46 | for (i = 0; i < buffer->page_count; i++) { | |
47 | ctx->page_count = ctx->buffer_size >> PAGE_SHIFT; | 47 | buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32); |
48 | ctx->pages = | 48 | if (buffer->pages[i] == NULL) |
49 | kzalloc(ctx->page_count * sizeof(ctx->pages[0]), GFP_KERNEL); | 49 | goto out_pages; |
50 | if (ctx->pages == NULL) | 50 | |
51 | goto fail_pages_alloc; | 51 | address = dma_map_page(card->device, buffer->pages[i], |
52 | 52 | 0, PAGE_SIZE, direction); | |
53 | p = ctx->buffer; | 53 | if (dma_mapping_error(address)) { |
54 | for (i = 0; i < ctx->page_count; i++, p += PAGE_SIZE) { | 54 | __free_page(buffer->pages[i]); |
55 | page = vmalloc_to_page(p); | 55 | goto out_pages; |
56 | ctx->pages[i] = dma_map_page(ctx->card->device, | 56 | } |
57 | page, 0, PAGE_SIZE, direction); | 57 | set_page_private(buffer->pages[i], address); |
58 | if (dma_mapping_error(ctx->pages[i])) | ||
59 | goto fail_mapping; | ||
60 | } | 58 | } |
61 | 59 | ||
62 | return 0; | 60 | return 0; |
63 | 61 | ||
64 | fail_mapping: | 62 | out_pages: |
65 | for (j = 0; j < i; j++) | 63 | for (j = 0; j < i; j++) { |
66 | dma_unmap_page(ctx->card->device, ctx->pages[j], | 64 | address = page_private(buffer->pages[j]); |
65 | dma_unmap_page(card->device, address, | ||
67 | PAGE_SIZE, DMA_TO_DEVICE); | 66 | PAGE_SIZE, DMA_TO_DEVICE); |
68 | fail_pages_alloc: | 67 | __free_page(buffer->pages[j]); |
69 | vfree(ctx->buffer); | 68 | } |
70 | fail_buffer_alloc: | 69 | kfree(buffer->pages); |
71 | return -ENOMEM; | 70 | out: |
71 | buffer->pages = NULL; | ||
72 | return retval; | ||
73 | } | ||
74 | |||
75 | int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma) | ||
76 | { | ||
77 | unsigned long uaddr; | ||
78 | int i, retval; | ||
79 | |||
80 | uaddr = vma->vm_start; | ||
81 | for (i = 0; i < buffer->page_count; i++) { | ||
82 | retval = vm_insert_page(vma, uaddr, buffer->pages[i]); | ||
83 | if (retval) | ||
84 | return retval; | ||
85 | uaddr += PAGE_SIZE; | ||
86 | } | ||
87 | |||
88 | return 0; | ||
72 | } | 89 | } |
73 | 90 | ||
74 | static void destroy_iso_buffer(struct fw_iso_context *ctx) | 91 | void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, |
92 | struct fw_card *card) | ||
75 | { | 93 | { |
76 | int i; | 94 | int i; |
95 | dma_addr_t address; | ||
77 | 96 | ||
78 | for (i = 0; i < ctx->page_count; i++) | 97 | for (i = 0; i < buffer->page_count; i++) { |
79 | dma_unmap_page(ctx->card->device, ctx->pages[i], | 98 | address = page_private(buffer->pages[i]); |
99 | dma_unmap_page(card->device, address, | ||
80 | PAGE_SIZE, DMA_TO_DEVICE); | 100 | PAGE_SIZE, DMA_TO_DEVICE); |
101 | __free_page(buffer->pages[i]); | ||
102 | } | ||
81 | 103 | ||
82 | kfree(ctx->pages); | 104 | kfree(buffer->pages); |
83 | vfree(ctx->buffer); | 105 | buffer->pages = NULL; |
84 | } | 106 | } |
85 | 107 | ||
86 | struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, | 108 | struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, |
87 | size_t buffer_size, | ||
88 | fw_iso_callback_t callback, | 109 | fw_iso_callback_t callback, |
89 | void *callback_data) | 110 | void *callback_data) |
90 | { | 111 | { |
91 | struct fw_iso_context *ctx; | 112 | struct fw_iso_context *ctx; |
92 | int retval; | ||
93 | 113 | ||
94 | ctx = card->driver->allocate_iso_context(card, type); | 114 | ctx = card->driver->allocate_iso_context(card, type); |
95 | if (IS_ERR(ctx)) | 115 | if (IS_ERR(ctx)) |
@@ -100,12 +120,6 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, | |||
100 | ctx->callback = callback; | 120 | ctx->callback = callback; |
101 | ctx->callback_data = callback_data; | 121 | ctx->callback_data = callback_data; |
102 | 122 | ||
103 | retval = setup_iso_buffer(ctx, buffer_size, DMA_TO_DEVICE); | ||
104 | if (retval < 0) { | ||
105 | card->driver->free_iso_context(ctx); | ||
106 | return ERR_PTR(retval); | ||
107 | } | ||
108 | |||
109 | return ctx; | 123 | return ctx; |
110 | } | 124 | } |
111 | EXPORT_SYMBOL(fw_iso_context_create); | 125 | EXPORT_SYMBOL(fw_iso_context_create); |
@@ -114,8 +128,6 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx) | |||
114 | { | 128 | { |
115 | struct fw_card *card = ctx->card; | 129 | struct fw_card *card = ctx->card; |
116 | 130 | ||
117 | destroy_iso_buffer(ctx); | ||
118 | |||
119 | card->driver->free_iso_context(ctx); | 131 | card->driver->free_iso_context(ctx); |
120 | } | 132 | } |
121 | EXPORT_SYMBOL(fw_iso_context_destroy); | 133 | EXPORT_SYMBOL(fw_iso_context_destroy); |
@@ -133,10 +145,12 @@ EXPORT_SYMBOL(fw_iso_context_send); | |||
133 | 145 | ||
134 | int | 146 | int |
135 | fw_iso_context_queue(struct fw_iso_context *ctx, | 147 | fw_iso_context_queue(struct fw_iso_context *ctx, |
136 | struct fw_iso_packet *packet, void *payload) | 148 | struct fw_iso_packet *packet, |
149 | struct fw_iso_buffer *buffer, | ||
150 | unsigned long payload) | ||
137 | { | 151 | { |
138 | struct fw_card *card = ctx->card; | 152 | struct fw_card *card = ctx->card; |
139 | 153 | ||
140 | return card->driver->queue_iso(ctx, packet, payload); | 154 | return card->driver->queue_iso(ctx, packet, buffer, payload); |
141 | } | 155 | } |
142 | EXPORT_SYMBOL(fw_iso_context_queue); | 156 | EXPORT_SYMBOL(fw_iso_context_queue); |