xref: /openbmc/linux/sound/firewire/packets-buffer.c (revision ac94be498f84f7327533b62faca4c3da64434904)
1da607e19SThomas 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  */
iso_packets_buffer_init(struct iso_packets_buffer * b,struct fw_unit * unit,unsigned int count,unsigned int packet_size,enum dma_data_direction direction)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;
40*1be3c1faSWenwen Wang 		goto err_packets;
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  */
iso_packets_buffer_destroy(struct iso_packets_buffer * b,struct fw_unit * unit)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