drivers: hv: dxgkrnl: Implement D3DKMTWaitSyncFile

Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
This commit is contained in:
Iouri Tarassov 2022-05-02 11:46:48 -07:00 коммит произвёл Allen Pais
Родитель ea2afebbd9
Коммит 6fc4a21466
8 изменённых файлов: 396 добавлений и 16 удалений

Просмотреть файл

@ -254,6 +254,10 @@ void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *sharedsyncobj,
struct dxgsyncobject *syncobj);
void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *sharedsyncobj,
struct dxgsyncobject *syncobj);
int dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj,
struct dxgprocess *process,
struct d3dkmthandle objecthandle);
void dxgsharedsyncobj_put(struct dxgsharedsyncobject *syncobj);
struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
struct dxgdevice *device,
@ -384,6 +388,8 @@ struct dxgprocess {
pid_t tgid;
/* how many time the process was opened */
struct kref process_kref;
/* protects the object memory */
struct kref process_mem_kref;
/*
* This handle table is used for all objects except dxgadapter
* The handle table lock order is higher than the local_handle_table
@ -405,6 +411,7 @@ struct dxgprocess {
struct dxgprocess *dxgprocess_create(void);
void dxgprocess_destroy(struct dxgprocess *process);
void dxgprocess_release(struct kref *refcount);
void dxgprocess_mem_release(struct kref *refcount);
int dxgprocess_open_adapter(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmthandle *handle);
@ -932,6 +939,10 @@ int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process,
struct d3dkmt_opensyncobjectfromnthandle2
*args,
struct dxgsyncobject *syncobj);
int dxgvmb_send_open_sync_object(struct dxgprocess *process,
struct d3dkmthandle device,
struct d3dkmthandle host_shared_syncobj,
struct d3dkmthandle *syncobj);
int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_queryallocationresidency

Просмотреть файл

@ -149,10 +149,11 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
spin_unlock_irq(&dxgglobal->host_event_list_mutex);
}
static void signal_dma_fence(struct dxghostevent *eventhdr)
static void dxg_signal_dma_fence(struct dxghostevent *eventhdr)
{
struct dxgsyncpoint *event = (struct dxgsyncpoint *)eventhdr;
DXG_TRACE("syncpoint: %px, fence: %lld", event, event->fence_value);
event->fence_value++;
list_del(&eventhdr->host_event_list_entry);
dma_fence_signal(&event->base);
@ -198,7 +199,7 @@ void dxgglobal_signal_host_event(u64 event_id)
if (event->event_type == dxghostevent_cpu_event)
signal_host_cpu_event(event);
else if (event->event_type == dxghostevent_dma_fence)
signal_dma_fence(event);
dxg_signal_dma_fence(event);
else
DXG_ERR("Unknown host event type");
break;
@ -355,6 +356,7 @@ static struct dxgprocess *dxgglobal_get_current_process(void)
if (entry->tgid == current->tgid) {
if (kref_get_unless_zero(&entry->process_kref)) {
process = entry;
kref_get(&entry->process_mem_kref);
DXG_TRACE("found dxgprocess");
} else {
DXG_TRACE("process is destroyed");
@ -405,6 +407,7 @@ static int dxgk_release(struct inode *n, struct file *f)
return -EINVAL;
kref_put(&process->process_kref, dxgprocess_release);
kref_put(&process->process_mem_kref, dxgprocess_mem_release);
f->private_data = NULL;
return 0;

Просмотреть файл

@ -39,6 +39,7 @@ struct dxgprocess *dxgprocess_create(void)
} else {
INIT_LIST_HEAD(&process->plistentry);
kref_init(&process->process_kref);
kref_init(&process->process_mem_kref);
mutex_lock(&dxgglobal->plistmutex);
list_add_tail(&process->plistentry,
@ -117,8 +118,17 @@ void dxgprocess_release(struct kref *refcount)
dxgprocess_destroy(process);
if (process->host_handle.v)
if (process->host_handle.v) {
dxgvmb_send_destroy_process(process->host_handle);
process->host_handle.v = 0;
}
}
void dxgprocess_mem_release(struct kref *refcount)
{
struct dxgprocess *process;
process = container_of(refcount, struct dxgprocess, process_mem_kref);
kfree(process);
}

Просмотреть файл

@ -9,6 +9,20 @@
* Dxgkrnl Graphics Driver
* Ioctl implementation
*
* dxgsyncpoint:
* - pointer to dxgsharedsyncobject
* - host_shared_handle_nt_reference incremented
* - list of (process, local syncobj d3dkmthandle) pairs
* wait for sync file
* - get dxgsyncpoint
* - if process doesn't have a local syncobj
* - create local dxgsyncobject
* - send open syncobj to the host
* - Send wait for syncobj to the context
* dxgsyncpoint destruction
* - walk the list of (process, local syncobj)
* - destroy syncobj
* - remove reference to dxgsharedsyncobject
*/
#include <linux/eventfd.h>
@ -45,12 +59,15 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
struct d3dkmt_createsyncfile args;
struct dxgsyncpoint *pt = NULL;
int ret = 0;
int fd = get_unused_fd_flags(O_CLOEXEC);
int fd;
struct sync_file *sync_file = NULL;
struct dxgdevice *device = NULL;
struct dxgadapter *adapter = NULL;
struct dxgsyncobject *syncobj = NULL;
struct d3dkmt_waitforsynchronizationobjectfromcpu waitargs = {};
bool device_lock_acquired = false;
fd = get_unused_fd_flags(O_CLOEXEC);
if (fd < 0) {
DXG_ERR("get_unused_fd_flags failed: %d", fd);
ret = fd;
@ -74,9 +91,9 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
ret = dxgdevice_acquire_lock_shared(device);
if (ret < 0) {
DXG_ERR("dxgdevice_acquire_lock_shared failed");
device = NULL;
goto cleanup;
}
device_lock_acquired = true;
adapter = device->adapter;
ret = dxgadapter_acquire_lock_shared(adapter);
@ -109,6 +126,30 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
}
dma_fence_put(&pt->base);
hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED);
syncobj = hmgrtable_get_object(&process->handle_table,
args.monitored_fence);
if (syncobj == NULL) {
DXG_ERR("invalid syncobj handle %x", args.monitored_fence.v);
ret = -EINVAL;
} else {
if (syncobj->shared) {
kref_get(&syncobj->syncobj_kref);
pt->shared_syncobj = syncobj->shared_owner;
}
}
hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED);
if (pt->shared_syncobj) {
ret = dxgsharedsyncobj_get_host_nt_handle(pt->shared_syncobj,
process,
args.monitored_fence);
if (ret)
pt->shared_syncobj = NULL;
}
if (ret)
goto cleanup;
waitargs.device = args.device;
waitargs.object_count = 1;
waitargs.objects = &args.monitored_fence;
@ -132,10 +173,15 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
fd_install(fd, sync_file->file);
cleanup:
if (syncobj && syncobj->shared)
kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
if (adapter)
dxgadapter_release_lock_shared(adapter);
if (device)
dxgdevice_release_lock_shared(device);
if (device) {
if (device_lock_acquired)
dxgdevice_release_lock_shared(device);
kref_put(&device->device_kref, dxgdevice_release);
}
if (ret) {
if (sync_file) {
fput(sync_file->file);
@ -151,6 +197,228 @@ cleanup:
return ret;
}
int dxgkio_open_syncobj_from_syncfile(struct dxgprocess *process,
void *__user inargs)
{
struct d3dkmt_opensyncobjectfromsyncfile args;
int ret = 0;
struct dxgsyncpoint *pt = NULL;
struct dma_fence *dmafence = NULL;
struct dxgdevice *device = NULL;
struct dxgadapter *adapter = NULL;
struct dxgsyncobject *syncobj = NULL;
struct d3dddi_synchronizationobject_flags flags = { };
struct d3dkmt_opensyncobjectfromnthandle2 openargs = { };
struct dxgglobal *dxgglobal = dxggbl();
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
ret = -EFAULT;
goto cleanup;
}
dmafence = sync_file_get_fence(args.sync_file_handle);
if (dmafence == NULL) {
DXG_ERR("failed to get dmafence from handle: %llx",
args.sync_file_handle);
ret = -EINVAL;
goto cleanup;
}
pt = to_syncpoint(dmafence);
if (pt->shared_syncobj == NULL) {
DXG_ERR("Sync object is not shared");
goto cleanup;
}
device = dxgprocess_device_by_handle(process, args.device);
if (device == NULL) {
DXG_ERR("dxgprocess_device_by_handle failed");
ret = -EINVAL;
goto cleanup;
}
ret = dxgdevice_acquire_lock_shared(device);
if (ret < 0) {
DXG_ERR("dxgdevice_acquire_lock_shared failed");
kref_put(&device->device_kref, dxgdevice_release);
device = NULL;
goto cleanup;
}
adapter = device->adapter;
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0) {
DXG_ERR("dxgadapter_acquire_lock_shared failed");
adapter = NULL;
goto cleanup;
}
flags.shared = 1;
flags.nt_security_sharing = 1;
syncobj = dxgsyncobject_create(process, device, adapter,
_D3DDDI_MONITORED_FENCE, flags);
if (syncobj == NULL) {
DXG_ERR("failed to create sync object");
ret = -ENOMEM;
goto cleanup;
}
dxgsharedsyncobj_add_syncobj(pt->shared_syncobj, syncobj);
/* Open the shared syncobj to get a local handle */
openargs.device = device->handle;
openargs.flags.shared = 1;
openargs.flags.nt_security_sharing = 1;
openargs.flags.no_signal = 1;
ret = dxgvmb_send_open_sync_object_nt(process,
&dxgglobal->channel, &openargs, syncobj);
if (ret) {
DXG_ERR("Failed to open shared syncobj on host");
goto cleanup;
}
hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
ret = hmgrtable_assign_handle(&process->handle_table,
syncobj,
HMGRENTRY_TYPE_DXGSYNCOBJECT,
openargs.sync_object);
if (ret == 0) {
syncobj->handle = openargs.sync_object;
kref_get(&syncobj->syncobj_kref);
}
hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
args.syncobj = openargs.sync_object;
args.fence_value = pt->fence_value;
args.fence_value_cpu_va = openargs.monitored_fence.fence_value_cpu_va;
args.fence_value_gpu_va = openargs.monitored_fence.fence_value_gpu_va;
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy output args");
ret = -EFAULT;
}
cleanup:
if (dmafence)
dma_fence_put(dmafence);
if (ret) {
if (syncobj) {
dxgsyncobject_destroy(process, syncobj);
kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
}
}
if (adapter)
dxgadapter_release_lock_shared(adapter);
if (device) {
dxgdevice_release_lock_shared(device);
kref_put(&device->device_kref, dxgdevice_release);
}
DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
return ret;
}
int dxgkio_wait_sync_file(struct dxgprocess *process, void *__user inargs)
{
struct d3dkmt_waitsyncfile args;
struct dma_fence *dmafence = NULL;
int ret = 0;
struct dxgsyncpoint *pt = NULL;
struct dxgdevice *device = NULL;
struct dxgadapter *adapter = NULL;
struct d3dkmthandle syncobj_handle = {};
bool device_lock_acquired = false;
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
ret = -EFAULT;
goto cleanup;
}
dmafence = sync_file_get_fence(args.sync_file_handle);
if (dmafence == NULL) {
DXG_ERR("failed to get dmafence from handle: %llx",
args.sync_file_handle);
ret = -EINVAL;
goto cleanup;
}
pt = to_syncpoint(dmafence);
device = dxgprocess_device_by_object_handle(process,
HMGRENTRY_TYPE_DXGCONTEXT,
args.context);
if (device == NULL) {
ret = -EINVAL;
goto cleanup;
}
ret = dxgdevice_acquire_lock_shared(device);
if (ret < 0) {
DXG_ERR("dxgdevice_acquire_lock_shared failed");
device = NULL;
goto cleanup;
}
device_lock_acquired = true;
adapter = device->adapter;
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0) {
DXG_ERR("dxgadapter_acquire_lock_shared failed");
adapter = NULL;
goto cleanup;
}
/* Open the shared syncobj to get a local handle */
if (pt->shared_syncobj == NULL) {
DXG_ERR("Sync object is not shared");
goto cleanup;
}
ret = dxgvmb_send_open_sync_object(process,
device->handle,
pt->shared_syncobj->host_shared_handle,
&syncobj_handle);
if (ret) {
DXG_ERR("Failed to open shared syncobj on host");
goto cleanup;
}
/* Ask the host to insert the syncobj to the context queue */
ret = dxgvmb_send_wait_sync_object_gpu(process, adapter,
args.context, 1,
&syncobj_handle,
&pt->fence_value,
false);
if (ret < 0) {
DXG_ERR("dxgvmb_send_wait_sync_object_cpu failed");
goto cleanup;
}
/*
* Destroy the local syncobject immediately. This will not unblock
* GPU waiters, but will unblock CPU waiter, which includes the sync
* file itself.
*/
ret = dxgvmb_send_destroy_sync_object(process, syncobj_handle);
cleanup:
if (adapter)
dxgadapter_release_lock_shared(adapter);
if (device) {
if (device_lock_acquired)
dxgdevice_release_lock_shared(device);
kref_put(&device->device_kref, dxgdevice_release);
}
if (dmafence)
dma_fence_put(dmafence);
DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
return ret;
}
static const char *dxgdmafence_get_driver_name(struct dma_fence *fence)
{
return "dxgkrnl";
@ -166,11 +434,16 @@ static void dxgdmafence_release(struct dma_fence *fence)
struct dxgsyncpoint *syncpoint;
syncpoint = to_syncpoint(fence);
if (syncpoint) {
if (syncpoint->hdr.event_id)
dxgglobal_get_host_event(syncpoint->hdr.event_id);
kfree(syncpoint);
}
if (syncpoint == NULL)
return;
if (syncpoint->hdr.event_id)
dxgglobal_get_host_event(syncpoint->hdr.event_id);
if (syncpoint->shared_syncobj)
dxgsharedsyncobj_put(syncpoint->shared_syncobj);
kfree(syncpoint);
}
static bool dxgdmafence_signaled(struct dma_fence *fence)

Просмотреть файл

@ -17,10 +17,13 @@
#include <linux/sync_file.h>
int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs);
int dxgkio_wait_sync_file(struct dxgprocess *process, void *__user inargs);
int dxgkio_open_syncobj_from_syncfile(struct dxgprocess *p, void *__user args);
struct dxgsyncpoint {
struct dxghostevent hdr;
struct dma_fence base;
struct dxgsharedsyncobject *shared_syncobj;
u64 fence_value;
u64 context;
spinlock_t lock;

Просмотреть файл

@ -796,6 +796,55 @@ cleanup:
return ret;
}
int dxgvmb_send_open_sync_object(struct dxgprocess *process,
struct d3dkmthandle device,
struct d3dkmthandle host_shared_syncobj,
struct d3dkmthandle *syncobj)
{
struct dxgkvmb_command_opensyncobject *command;
struct dxgkvmb_command_opensyncobject_return result = { };
int ret;
struct dxgvmbusmsg msg;
struct dxgglobal *dxgglobal = dxggbl();
ret = init_message(&msg, NULL, process, sizeof(*command));
if (ret)
return ret;
command = (void *)msg.msg;
command_vm_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_OPENSYNCOBJECT,
process->host_handle);
command->device = device;
command->global_sync_object = host_shared_syncobj;
command->flags.shared = 1;
command->flags.nt_security_sharing = 1;
command->flags.no_signal = 1;
ret = dxgglobal_acquire_channel_lock();
if (ret < 0)
goto cleanup;
ret = dxgvmb_send_sync_msg(&dxgglobal->channel, msg.hdr, msg.size,
&result, sizeof(result));
dxgglobal_release_channel_lock();
if (ret < 0)
goto cleanup;
ret = ntstatus2int(result.status);
if (ret < 0)
goto cleanup;
*syncobj = result.sync_object;
cleanup:
free_message(&msg, process);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
}
int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process,
struct d3dkmthandle object,
struct d3dkmthandle *shared_handle)

Просмотреть файл

@ -36,10 +36,8 @@ static char *errorstr(int ret)
}
#endif
static int dxgsyncobj_release(struct inode *inode, struct file *file)
void dxgsharedsyncobj_put(struct dxgsharedsyncobject *syncobj)
{
struct dxgsharedsyncobject *syncobj = file->private_data;
DXG_TRACE("Release syncobj: %p", syncobj);
mutex_lock(&syncobj->fd_mutex);
kref_get(&syncobj->ssyncobj_kref);
@ -56,6 +54,13 @@ static int dxgsyncobj_release(struct inode *inode, struct file *file)
}
mutex_unlock(&syncobj->fd_mutex);
kref_put(&syncobj->ssyncobj_kref, dxgsharedsyncobj_release);
}
static int dxgsyncobj_release(struct inode *inode, struct file *file)
{
struct dxgsharedsyncobject *syncobj = file->private_data;
dxgsharedsyncobj_put(syncobj);
return 0;
}
@ -4478,7 +4483,7 @@ cleanup:
return ret;
}
static int
int
dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj,
struct dxgprocess *process,
struct d3dkmthandle objecthandle)
@ -5226,6 +5231,9 @@ static struct ioctl_desc ioctls[] = {
/* 0x43 */ {dxgkio_query_statistics, LX_DXQUERYSTATISTICS},
/* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST},
/* 0x45 */ {dxgkio_create_sync_file, LX_DXCREATESYNCFILE},
/* 0x46 */ {dxgkio_wait_sync_file, LX_DXWAITSYNCFILE},
/* 0x46 */ {dxgkio_open_syncobj_from_syncfile,
LX_DXOPENSYNCOBJECTFROMSYNCFILE},
};
/*

Просмотреть файл

@ -1561,6 +1561,25 @@ struct d3dkmt_createsyncfile {
__u64 sync_file_handle; /* out */
};
struct d3dkmt_waitsyncfile {
__u64 sync_file_handle;
struct d3dkmthandle context;
__u32 reserved;
};
struct d3dkmt_opensyncobjectfromsyncfile {
__u64 sync_file_handle;
struct d3dkmthandle device;
struct d3dkmthandle syncobj; /* out */
__u64 fence_value; /* out */
#ifdef __KERNEL__
void *fence_value_cpu_va; /* out */
#else
__u64 fence_value_cpu_va; /* out */
#endif
__u64 fence_value_gpu_va; /* out */
};
/*
* Dxgkrnl Graphics Port Driver ioctl definitions
*
@ -1686,5 +1705,9 @@ struct d3dkmt_createsyncfile {
_IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost)
#define LX_DXCREATESYNCFILE \
_IOWR(0x47, 0x45, struct d3dkmt_createsyncfile)
#define LX_DXWAITSYNCFILE \
_IOWR(0x47, 0x46, struct d3dkmt_waitsyncfile)
#define LX_DXOPENSYNCOBJECTFROMSYNCFILE \
_IOWR(0x47, 0x47, struct d3dkmt_opensyncobjectfromsyncfile)
#endif /* _D3DKMTHK_H */