1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * helpers for managing a buffer for many packets |
4 | * |
5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
6 | */ |
7 | |
8 | #include <linux/firewire.h> |
9 | #include <linux/export.h> |
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 | |
30 | b->packets = kmalloc_array(n: count, size: sizeof(*b->packets), GFP_KERNEL); |
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; |
40 | goto err_packets; |
41 | } |
42 | pages = DIV_ROUND_UP(count, packets_per_page); |
43 | |
44 | err = fw_iso_buffer_init(buffer: &b->iso_buffer, fw_parent_device(unit)->card, |
45 | page_count: 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(objp: b->packets); |
61 | error: |
62 | return err; |
63 | } |
64 | EXPORT_SYMBOL(iso_packets_buffer_init); |
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(buffer: &b->iso_buffer, fw_parent_device(unit)->card); |
75 | kfree(objp: b->packets); |
76 | } |
77 | EXPORT_SYMBOL(iso_packets_buffer_destroy); |
78 | |