File Index
Files and directories
Sign in
FILE

iova_allocator.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/vfio/lib/iova_allocator.c C
 1// SPDX-License-Identifier: GPL-2.0-only
 2#include <dirent.h>
 3#include <fcntl.h>
 4#include <libgen.h>
 5#include <stdint.h>
 6#include <stdlib.h>
 7#include <string.h>
 8#include <unistd.h>
 9
10#include <sys/eventfd.h>
11#include <sys/ioctl.h>
12#include <sys/mman.h>
13
14#include <linux/iommufd.h>
15#include <linux/limits.h>
16#include <linux/mman.h>
17#include <linux/overflow.h>
18#include <linux/types.h>
19#include <linux/vfio.h>
20
21#include <libvfio.h>
22
23struct iova_allocator *iova_allocator_init(struct iommu *iommu)
24{
25	struct iova_allocator *allocator;
26	struct iommu_iova_range *ranges;
27	u32 nranges;
28
29	ranges = iommu_iova_ranges(iommu, &nranges);
30	VFIO_ASSERT_NOT_NULL(ranges);
31
32	allocator = malloc(sizeof(*allocator));
33	VFIO_ASSERT_NOT_NULL(allocator);
34
35	*allocator = (struct iova_allocator){
36		.ranges = ranges,
37		.nranges = nranges,
38		.range_idx = 0,
39		.range_offset = 0,
40	};
41
42	return allocator;
43}
44
45void iova_allocator_cleanup(struct iova_allocator *allocator)
46{
47	free(allocator->ranges);
48	free(allocator);
49}
50
51iova_t iova_allocator_alloc(struct iova_allocator *allocator, size_t size)
52{
53	VFIO_ASSERT_GT(size, 0, "Invalid size arg, zero\n");
54	VFIO_ASSERT_EQ(size & (size - 1), 0, "Invalid size arg, non-power-of-2\n");
55
56	for (;;) {
57		struct iommu_iova_range *range;
58		iova_t iova, last;
59
60		VFIO_ASSERT_LT(allocator->range_idx, allocator->nranges,
61			       "IOVA allocator out of space\n");
62
63		range = &allocator->ranges[allocator->range_idx];
64		iova = range->start + allocator->range_offset;
65
66		/* Check for sufficient space at the current offset */
67		if (check_add_overflow(iova, size - 1, &last) ||
68		    last > range->last)
69			goto next_range;
70
71		/* Align iova to size */
72		iova = last & ~(size - 1);
73
74		/* Check for sufficient space at the aligned iova */
75		if (check_add_overflow(iova, size - 1, &last) ||
76		    last > range->last)
77			goto next_range;
78
79		if (last == range->last) {
80			allocator->range_idx++;
81			allocator->range_offset = 0;
82		} else {
83			allocator->range_offset = last - range->start + 1;
84		}
85
86		return iova;
87
88next_range:
89		allocator->range_idx++;
90		allocator->range_offset = 0;
91	}
92}
93
~/ Read-only file preview.