1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/dma-mapping.h>
24#include <linux/errno.h>
25#include <linux/firewire.h>
26#include <linux/firewire-constants.h>
27#include <linux/kernel.h>
28#include <linux/mm.h>
29#include <linux/slab.h>
30#include <linux/spinlock.h>
31#include <linux/vmalloc.h>
32#include <linux/export.h>
33
34#include <asm/byteorder.h>
35
36#include "core.h"
37
38
39
40
41
42int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count)
43{
44 int i;
45
46 buffer->page_count = 0;
47 buffer->page_count_mapped = 0;
48 buffer->pages = kmalloc_array(page_count, sizeof(buffer->pages[0]),
49 GFP_KERNEL);
50 if (buffer->pages == NULL)
51 return -ENOMEM;
52
53 for (i = 0; i < page_count; i++) {
54 buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
55 if (buffer->pages[i] == NULL)
56 break;
57 }
58 buffer->page_count = i;
59 if (i < page_count) {
60 fw_iso_buffer_destroy(buffer, NULL);
61 return -ENOMEM;
62 }
63
64 return 0;
65}
66
67int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
68 enum dma_data_direction direction)
69{
70 dma_addr_t address;
71 int i;
72
73 buffer->direction = direction;
74
75 for (i = 0; i < buffer->page_count; i++) {
76 address = dma_map_page(card->device, buffer->pages[i],
77 0, PAGE_SIZE, direction);
78 if (dma_mapping_error(card->device, address))
79 break;
80
81 set_page_private(buffer->pages[i], address);
82 }
83 buffer->page_count_mapped = i;
84 if (i < buffer->page_count)
85 return -ENOMEM;
86
87 return 0;
88}
89
90int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
91 int page_count, enum dma_data_direction direction)
92{
93 int ret;
94
95 ret = fw_iso_buffer_alloc(buffer, page_count);
96 if (ret < 0)
97 return ret;
98
99 ret = fw_iso_buffer_map_dma(buffer, card, direction);
100 if (ret < 0)
101 fw_iso_buffer_destroy(buffer, card);
102
103 return ret;
104}
105EXPORT_SYMBOL(fw_iso_buffer_init);
106
107int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
108 struct vm_area_struct *vma)
109{
110 unsigned long uaddr;
111 int i, err;
112
113 uaddr = vma->vm_start;
114 for (i = 0; i < buffer->page_count; i++) {
115 err = vm_insert_page(vma, uaddr, buffer->pages[i]);
116 if (err)
117 return err;
118
119 uaddr += PAGE_SIZE;
120 }
121
122 return 0;
123}
124
125void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
126 struct fw_card *card)
127{
128 int i;
129 dma_addr_t address;
130
131 for (i = 0; i < buffer->page_count_mapped; i++) {
132 address = page_private(buffer->pages[i]);
133 dma_unmap_page(card->device, address,
134 PAGE_SIZE, buffer->direction);
135 }
136 for (i = 0; i < buffer->page_count; i++)
137 __free_page(buffer->pages[i]);
138
139 kfree(buffer->pages);
140 buffer->pages = NULL;
141 buffer->page_count = 0;
142 buffer->page_count_mapped = 0;
143}
144EXPORT_SYMBOL(fw_iso_buffer_destroy);
145
146
147size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed)
148{
149 size_t i;
150 dma_addr_t address;
151 ssize_t offset;
152
153 for (i = 0; i < buffer->page_count; i++) {
154 address = page_private(buffer->pages[i]);
155 offset = (ssize_t)completed - (ssize_t)address;
156 if (offset > 0 && offset <= PAGE_SIZE)
157 return (i << PAGE_SHIFT) + offset;
158 }
159
160 return 0;
161}
162
163struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
164 int type, int channel, int speed, size_t header_size,
165 fw_iso_callback_t callback, void *callback_data)
166{
167 struct fw_iso_context *ctx;
168
169 ctx = card->driver->allocate_iso_context(card,
170 type, channel, header_size);
171 if (IS_ERR(ctx))
172 return ctx;
173
174 ctx->card = card;
175 ctx->type = type;
176 ctx->channel = channel;
177 ctx->speed = speed;
178 ctx->header_size = header_size;
179 ctx->callback.sc = callback;
180 ctx->callback_data = callback_data;
181
182 return ctx;
183}
184EXPORT_SYMBOL(fw_iso_context_create);
185
186void fw_iso_context_destroy(struct fw_iso_context *ctx)
187{
188 ctx->card->driver->free_iso_context(ctx);
189}
190EXPORT_SYMBOL(fw_iso_context_destroy);
191
192int fw_iso_context_start(struct fw_iso_context *ctx,
193 int cycle, int sync, int tags)
194{
195 return ctx->card->driver->start_iso(ctx, cycle, sync, tags);
196}
197EXPORT_SYMBOL(fw_iso_context_start);
198
199int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels)
200{
201 return ctx->card->driver->set_iso_channels(ctx, channels);
202}
203
204int fw_iso_context_queue(struct fw_iso_context *ctx,
205 struct fw_iso_packet *packet,
206 struct fw_iso_buffer *buffer,
207 unsigned long payload)
208{
209 return ctx->card->driver->queue_iso(ctx, packet, buffer, payload);
210}
211EXPORT_SYMBOL(fw_iso_context_queue);
212
213void fw_iso_context_queue_flush(struct fw_iso_context *ctx)
214{
215 ctx->card->driver->flush_queue_iso(ctx);
216}
217EXPORT_SYMBOL(fw_iso_context_queue_flush);
218
219int fw_iso_context_flush_completions(struct fw_iso_context *ctx)
220{
221 return ctx->card->driver->flush_iso_completions(ctx);
222}
223EXPORT_SYMBOL(fw_iso_context_flush_completions);
224
225int fw_iso_context_stop(struct fw_iso_context *ctx)
226{
227 return ctx->card->driver->stop_iso(ctx);
228}
229EXPORT_SYMBOL(fw_iso_context_stop);
230
231
232
233
234
235static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
236 int bandwidth, bool allocate)
237{
238 int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0;
239 __be32 data[2];
240
241
242
243
244
245
246 for (try = 0; try < 5; try++) {
247 new = allocate ? old - bandwidth : old + bandwidth;
248 if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL)
249 return -EBUSY;
250
251 data[0] = cpu_to_be32(old);
252 data[1] = cpu_to_be32(new);
253 switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
254 irm_id, generation, SCODE_100,
255 CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
256 data, 8)) {
257 case RCODE_GENERATION:
258
259 return allocate ? -EAGAIN : bandwidth;
260
261 case RCODE_COMPLETE:
262 if (be32_to_cpup(data) == old)
263 return bandwidth;
264
265 old = be32_to_cpup(data);
266
267 }
268 }
269
270 return -EIO;
271}
272
273static int manage_channel(struct fw_card *card, int irm_id, int generation,
274 u32 channels_mask, u64 offset, bool allocate)
275{
276 __be32 bit, all, old;
277 __be32 data[2];
278 int channel, ret = -EIO, retry = 5;
279
280 old = all = allocate ? cpu_to_be32(~0) : 0;
281
282 for (channel = 0; channel < 32; channel++) {
283 if (!(channels_mask & 1 << channel))
284 continue;
285
286 ret = -EBUSY;
287
288 bit = cpu_to_be32(1 << (31 - channel));
289 if ((old & bit) != (all & bit))
290 continue;
291
292 data[0] = old;
293 data[1] = old ^ bit;
294 switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
295 irm_id, generation, SCODE_100,
296 offset, data, 8)) {
297 case RCODE_GENERATION:
298
299 return allocate ? -EAGAIN : channel;
300
301 case RCODE_COMPLETE:
302 if (data[0] == old)
303 return channel;
304
305 old = data[0];
306
307
308 if ((data[0] & bit) == (data[1] & bit))
309 continue;
310
311
312 default:
313 if (retry) {
314 retry--;
315 channel--;
316 } else {
317 ret = -EIO;
318 }
319 }
320 }
321
322 return ret;
323}
324
325static void deallocate_channel(struct fw_card *card, int irm_id,
326 int generation, int channel)
327{
328 u32 mask;
329 u64 offset;
330
331 mask = channel < 32 ? 1 << channel : 1 << (channel - 32);
332 offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
333 CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO;
334
335 manage_channel(card, irm_id, generation, mask, offset, false);
336}
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369void fw_iso_resource_manage(struct fw_card *card, int generation,
370 u64 channels_mask, int *channel, int *bandwidth,
371 bool allocate)
372{
373 u32 channels_hi = channels_mask;
374 u32 channels_lo = channels_mask >> 32;
375 int irm_id, ret, c = -EINVAL;
376
377 spin_lock_irq(&card->lock);
378 irm_id = card->irm_node->node_id;
379 spin_unlock_irq(&card->lock);
380
381 if (channels_hi)
382 c = manage_channel(card, irm_id, generation, channels_hi,
383 CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI,
384 allocate);
385 if (channels_lo && c < 0) {
386 c = manage_channel(card, irm_id, generation, channels_lo,
387 CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO,
388 allocate);
389 if (c >= 0)
390 c += 32;
391 }
392 *channel = c;
393
394 if (allocate && channels_mask != 0 && c < 0)
395 *bandwidth = 0;
396
397 if (*bandwidth == 0)
398 return;
399
400 ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate);
401 if (ret < 0)
402 *bandwidth = 0;
403
404 if (allocate && ret < 0) {
405 if (c >= 0)
406 deallocate_channel(card, irm_id, generation, c);
407 *channel = ret;
408 }
409}
410EXPORT_SYMBOL(fw_iso_resource_manage);
411