1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
// SPDX-License-Identifier: MIT
/*
* Copyright © 2022 Intel Corporation
*/
#include "igt.h"
#include "igt_vgem.h"
#include "sw_sync.h"
#include "dmabuf_sync_file.h"
/**
* SECTION: dmabuf_sync_file
* @short_description: DMABUF importing/exporting fencing support library
* @title: DMABUF Sync File
* @include: dmabuf_sync_file.h
*/
struct igt_dma_buf_sync_file {
__u32 flags;
__s32 fd;
};
#define IGT_DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct igt_dma_buf_sync_file)
#define IGT_DMA_BUF_IOCTL_IMPORT_SYNC_FILE _IOW(DMA_BUF_BASE, 3, struct igt_dma_buf_sync_file)
/**
* has_dmabuf_export_sync_file:
* @fd: The open drm fd
*
* Check if the kernel supports exporting a sync file from dmabuf.
*/
bool has_dmabuf_export_sync_file(int fd)
{
struct vgem_bo bo;
int dmabuf, ret;
struct igt_dma_buf_sync_file arg;
bo.width = 1;
bo.height = 1;
bo.bpp = 32;
vgem_create(fd, &bo);
dmabuf = prime_handle_to_fd(fd, bo.handle);
gem_close(fd, bo.handle);
arg.flags = DMA_BUF_SYNC_WRITE;
arg.fd = -1;
ret = igt_ioctl(dmabuf, IGT_DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &arg);
close(dmabuf);
return (ret == 0 || errno == ENOTTY);
}
/**
* dmabuf_export_sync_file:
* @dmabuf: The dmabuf fd
* @flags: The flags to control the behaviour
*
* Take a snapshot of the current dma-resv fences in the dmabuf, and export as a
* syncfile. The @flags should at least specify either DMA_BUF_SYNC_WRITE or
* DMA_BUF_SYNC_READ, depending on if we care about the read or write fences.
*/
int dmabuf_export_sync_file(int dmabuf, uint32_t flags)
{
struct igt_dma_buf_sync_file arg;
arg.flags = flags;
arg.fd = -1;
do_ioctl(dmabuf, IGT_DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &arg);
return arg.fd;
}
/**
* has_dmabuf_import_sync_file:
* @fd: The open drm fd
*
* Check if the kernel supports importing a sync file into a dmabuf.
*/
bool has_dmabuf_import_sync_file(int fd)
{
struct vgem_bo bo;
int dmabuf, timeline, fence, ret;
struct igt_dma_buf_sync_file arg;
bo.width = 1;
bo.height = 1;
bo.bpp = 32;
vgem_create(fd, &bo);
dmabuf = prime_handle_to_fd(fd, bo.handle);
gem_close(fd, bo.handle);
timeline = sw_sync_timeline_create();
fence = sw_sync_timeline_create_fence(timeline, 1);
sw_sync_timeline_inc(timeline, 1);
arg.flags = DMA_BUF_SYNC_RW;
arg.fd = fence;
ret = igt_ioctl(dmabuf, IGT_DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &arg);
close(dmabuf);
close(fence);
return (ret == 0 || errno == ENOTTY);
}
/**
* dmabuf_import_sync_file:
* @dmabuf: The dmabuf fd
* @flags: The flags to control the behaviour
* @sync_fd: The sync file (i.e our fence) to import
*
* Import the sync file @sync_fd, into the dmabuf. The @flags should at least
* specify DMA_BUF_SYNC_WRITE or DMA_BUF_SYNC_READ, depending on if we are
* importing the @sync_fd as a read or write fence.
*/
void dmabuf_import_sync_file(int dmabuf, uint32_t flags, int sync_fd)
{
struct igt_dma_buf_sync_file arg;
arg.flags = flags;
arg.fd = sync_fd;
do_ioctl(dmabuf, IGT_DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &arg);
}
/**
* dmabuf_import_timeline_fence:
* @dmabuf: The dmabuf fd
* @flags: The flags to control the behaviour
* @timeline: The sync file timeline where the new fence is created
* @seqno: The sequence number to use for the fence
*
* Create a new fence as part of @timeline, and import as a sync file into the
* dmabuf. The @flags should at least specify DMA_BUF_SYNC_WRITE or
* DMA_BUF_SYNC_READ, depending on if we are importing the new fence as a read
* or write fence.
*/
void dmabuf_import_timeline_fence(int dmabuf, uint32_t flags,
int timeline, uint32_t seqno)
{
int fence;
fence = sw_sync_timeline_create_fence(timeline, seqno);
dmabuf_import_sync_file(dmabuf, flags, fence);
close(fence);
}
/**
* dmabuf_busy:
* @dmabuf: The dmabuf fd
* @flags: The flags to control the behaviour
*
* Check if the fences in the dmabuf are still busy. The @flags should at least
* specify DMA_BUF_SYNC_WRITE or DMA_BUF_SYNC_READ, depending on if we are
* checking if the read or read fences have all signalled. Or DMA_BUF_SYNC_RW if
* we care about both.
*/
bool dmabuf_busy(int dmabuf, uint32_t flags)
{
struct pollfd pfd = { .fd = dmabuf };
/* If DMA_BUF_SYNC_WRITE is set, we don't want to set POLLIN or
* else poll() may return a non-zero value if there are only read
* fences because POLLIN is ready even if POLLOUT isn't.
*/
if (flags & DMA_BUF_SYNC_WRITE)
pfd.events |= POLLOUT;
else if (flags & DMA_BUF_SYNC_READ)
pfd.events |= POLLIN;
return poll(&pfd, 1, 0) == 0;
}
/**
* sync_file_busy:
* @sync_file: The sync file to check
*
* Check if the @sync_file is still busy or not.
*/
bool sync_file_busy(int sync_file)
{
struct pollfd pfd = { .fd = sync_file, .events = POLLIN };
return poll(&pfd, 1, 0) == 0;
}
/**
* dmabuf_sync_file_busy:
* @dmabuf: The dmabuf fd
* @flags: The flags to control the behaviour
*
* Export the current fences in @dmabuf as a sync file and check if still busy.
* The @flags should at least contain DMA_BUF_SYNC_WRITE or DMA_BUF_SYNC_READ,
* to specify which fences are to be exported from the @dmabuf and checked if
* busy. Or DMA_BUF_SYNC_RW if we care about both.
*/
bool dmabuf_sync_file_busy(int dmabuf, uint32_t flags)
{
int sync_file;
bool busy;
sync_file = dmabuf_export_sync_file(dmabuf, flags);
busy = sync_file_busy(sync_file);
close(sync_file);
return busy;
}
|