diff options
author | Kristian Høgsberg <krh@redhat.com> | 2007-02-16 17:34:38 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-03-09 16:02:57 -0500 |
commit | 9aad8125389a7a2990dee72d7892e22330a945eb (patch) | |
tree | 2566a8985837b000990db7e16b17547d3747141b /drivers/firewire/fw-iso.c | |
parent | 6e2e8424d310507fa044649435114217826ed78a (diff) |
firewire: Split the iso buffer out from fw_iso_context and avoid vmalloc.
This patch splits out the iso buffer so we can initialize it at mmap
time with the size provided in the mmap call. Furthermore, allocate
the backing pages using alloc_page to avoid setting up kernel side
virtual memory mappings for the pages.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
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); |