]>
Commit | Line | Data |
---|---|---|
da607e19 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
31ef9134 CL |
2 | /* |
3 | * helpers for managing a buffer for many packets | |
4 | * | |
5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | |
31ef9134 CL |
6 | */ |
7 | ||
8 | #include <linux/firewire.h> | |
d81a6d71 | 9 | #include <linux/export.h> |
31ef9134 CL |
10 | #include <linux/slab.h> |
11 | #include "packets-buffer.h" | |
12 | ||
13 | /** | |
14 | * iso_packets_buffer_init - allocates the memory for packets | |
15 | * @b: the buffer structure to initialize | |
16 | * @unit: the device at the other end of the stream | |
17 | * @count: the number of packets | |
18 | * @packet_size: the (maximum) size of a packet, in bytes | |
19 | * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE | |
20 | */ | |
21 | int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, | |
22 | unsigned int count, unsigned int packet_size, | |
23 | enum dma_data_direction direction) | |
24 | { | |
25 | unsigned int packets_per_page, pages; | |
26 | unsigned int i, page_index, offset_in_page; | |
27 | void *p; | |
28 | int err; | |
29 | ||
6da2ec56 | 30 | b->packets = kmalloc_array(count, sizeof(*b->packets), GFP_KERNEL); |
31ef9134 CL |
31 | if (!b->packets) { |
32 | err = -ENOMEM; | |
33 | goto error; | |
34 | } | |
35 | ||
36 | packet_size = L1_CACHE_ALIGN(packet_size); | |
37 | packets_per_page = PAGE_SIZE / packet_size; | |
38 | if (WARN_ON(!packets_per_page)) { | |
39 | err = -EINVAL; | |
1be3c1fa | 40 | goto err_packets; |
31ef9134 CL |
41 | } |
42 | pages = DIV_ROUND_UP(count, packets_per_page); | |
43 | ||
44 | err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card, | |
45 | pages, direction); | |
46 | if (err < 0) | |
47 | goto err_packets; | |
48 | ||
49 | for (i = 0; i < count; ++i) { | |
50 | page_index = i / packets_per_page; | |
51 | p = page_address(b->iso_buffer.pages[page_index]); | |
52 | offset_in_page = (i % packets_per_page) * packet_size; | |
53 | b->packets[i].buffer = p + offset_in_page; | |
54 | b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page; | |
55 | } | |
56 | ||
57 | return 0; | |
58 | ||
59 | err_packets: | |
60 | kfree(b->packets); | |
61 | error: | |
62 | return err; | |
63 | } | |
3a691b28 | 64 | EXPORT_SYMBOL(iso_packets_buffer_init); |
31ef9134 CL |
65 | |
66 | /** | |
67 | * iso_packets_buffer_destroy - frees packet buffer resources | |
68 | * @b: the buffer structure to free | |
69 | * @unit: the device at the other end of the stream | |
70 | */ | |
71 | void iso_packets_buffer_destroy(struct iso_packets_buffer *b, | |
72 | struct fw_unit *unit) | |
73 | { | |
74 | fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); | |
75 | kfree(b->packets); | |
76 | } | |
3a691b28 | 77 | EXPORT_SYMBOL(iso_packets_buffer_destroy); |