1*da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 231ef9134SClemens Ladisch /* 331ef9134SClemens Ladisch * helpers for managing a buffer for many packets 431ef9134SClemens Ladisch * 531ef9134SClemens Ladisch * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 631ef9134SClemens Ladisch */ 731ef9134SClemens Ladisch 831ef9134SClemens Ladisch #include <linux/firewire.h> 9d81a6d71SPaul Gortmaker #include <linux/export.h> 1031ef9134SClemens Ladisch #include <linux/slab.h> 1131ef9134SClemens Ladisch #include "packets-buffer.h" 1231ef9134SClemens Ladisch 1331ef9134SClemens Ladisch /** 1431ef9134SClemens Ladisch * iso_packets_buffer_init - allocates the memory for packets 1531ef9134SClemens Ladisch * @b: the buffer structure to initialize 1631ef9134SClemens Ladisch * @unit: the device at the other end of the stream 1731ef9134SClemens Ladisch * @count: the number of packets 1831ef9134SClemens Ladisch * @packet_size: the (maximum) size of a packet, in bytes 1931ef9134SClemens Ladisch * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE 2031ef9134SClemens Ladisch */ 2131ef9134SClemens Ladisch int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, 2231ef9134SClemens Ladisch unsigned int count, unsigned int packet_size, 2331ef9134SClemens Ladisch enum dma_data_direction direction) 2431ef9134SClemens Ladisch { 2531ef9134SClemens Ladisch unsigned int packets_per_page, pages; 2631ef9134SClemens Ladisch unsigned int i, page_index, offset_in_page; 2731ef9134SClemens Ladisch void *p; 2831ef9134SClemens Ladisch int err; 2931ef9134SClemens Ladisch 306da2ec56SKees Cook b->packets = kmalloc_array(count, sizeof(*b->packets), GFP_KERNEL); 3131ef9134SClemens Ladisch if (!b->packets) { 3231ef9134SClemens Ladisch err = -ENOMEM; 3331ef9134SClemens Ladisch goto error; 3431ef9134SClemens Ladisch } 3531ef9134SClemens Ladisch 3631ef9134SClemens Ladisch packet_size = L1_CACHE_ALIGN(packet_size); 3731ef9134SClemens Ladisch packets_per_page = PAGE_SIZE / packet_size; 3831ef9134SClemens Ladisch if (WARN_ON(!packets_per_page)) { 3931ef9134SClemens Ladisch err = -EINVAL; 4031ef9134SClemens Ladisch goto error; 4131ef9134SClemens Ladisch } 4231ef9134SClemens Ladisch pages = DIV_ROUND_UP(count, packets_per_page); 4331ef9134SClemens Ladisch 4431ef9134SClemens Ladisch err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card, 4531ef9134SClemens Ladisch pages, direction); 4631ef9134SClemens Ladisch if (err < 0) 4731ef9134SClemens Ladisch goto err_packets; 4831ef9134SClemens Ladisch 4931ef9134SClemens Ladisch for (i = 0; i < count; ++i) { 5031ef9134SClemens Ladisch page_index = i / packets_per_page; 5131ef9134SClemens Ladisch p = page_address(b->iso_buffer.pages[page_index]); 5231ef9134SClemens Ladisch offset_in_page = (i % packets_per_page) * packet_size; 5331ef9134SClemens Ladisch b->packets[i].buffer = p + offset_in_page; 5431ef9134SClemens Ladisch b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page; 5531ef9134SClemens Ladisch } 5631ef9134SClemens Ladisch 5731ef9134SClemens Ladisch return 0; 5831ef9134SClemens Ladisch 5931ef9134SClemens Ladisch err_packets: 6031ef9134SClemens Ladisch kfree(b->packets); 6131ef9134SClemens Ladisch error: 6231ef9134SClemens Ladisch return err; 6331ef9134SClemens Ladisch } 643a691b28SClemens Ladisch EXPORT_SYMBOL(iso_packets_buffer_init); 6531ef9134SClemens Ladisch 6631ef9134SClemens Ladisch /** 6731ef9134SClemens Ladisch * iso_packets_buffer_destroy - frees packet buffer resources 6831ef9134SClemens Ladisch * @b: the buffer structure to free 6931ef9134SClemens Ladisch * @unit: the device at the other end of the stream 7031ef9134SClemens Ladisch */ 7131ef9134SClemens Ladisch void iso_packets_buffer_destroy(struct iso_packets_buffer *b, 7231ef9134SClemens Ladisch struct fw_unit *unit) 7331ef9134SClemens Ladisch { 7431ef9134SClemens Ladisch fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); 7531ef9134SClemens Ladisch kfree(b->packets); 7631ef9134SClemens Ladisch } 773a691b28SClemens Ladisch EXPORT_SYMBOL(iso_packets_buffer_destroy); 78