mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
483 lines
14 KiB
Diff
483 lines
14 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Iouri Tarassov <iourit@linux.microsoft.com>
|
|
Date: Tue, 22 Mar 2022 11:02:49 -0700
|
|
Subject: drivers: hv: dxgkrnl: Creation of dxgsyncfile objects
|
|
|
|
Implement the ioctl to create a dxgsyncfile object
|
|
(LX_DXCREATESYNCFILE). This object is a wrapper around a monitored
|
|
fence sync object and a fence value.
|
|
|
|
dxgsyncfile is built on top of the Linux sync_file object and
|
|
provides a way for the user mode to synchronize with the execution
|
|
of the device DMA packets.
|
|
|
|
The ioctl creates a dxgsyncfile object for the given GPU synchronization
|
|
object and a fence value. A file descriptor of the sync_file object
|
|
is returned to the caller. The caller could wait for the object by using
|
|
poll(). When the underlying GPU synchronization object is signaled on
|
|
the host, the host sends a message to the virtual machine and the
|
|
sync_file object is signaled.
|
|
|
|
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
|
|
[kms: Forward port to v6.1]
|
|
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
|
|
---
|
|
drivers/hv/dxgkrnl/Kconfig | 2 +
|
|
drivers/hv/dxgkrnl/Makefile | 2 +-
|
|
drivers/hv/dxgkrnl/dxgkrnl.h | 2 +
|
|
drivers/hv/dxgkrnl/dxgmodule.c | 12 +
|
|
drivers/hv/dxgkrnl/dxgsyncfile.c | 215 ++++++++++
|
|
drivers/hv/dxgkrnl/dxgsyncfile.h | 30 ++
|
|
drivers/hv/dxgkrnl/dxgvmbus.c | 33 +-
|
|
drivers/hv/dxgkrnl/ioctl.c | 5 +-
|
|
include/uapi/misc/d3dkmthk.h | 9 +
|
|
9 files changed, 294 insertions(+), 16 deletions(-)
|
|
|
|
diff --git a/drivers/hv/dxgkrnl/Kconfig b/drivers/hv/dxgkrnl/Kconfig
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/Kconfig
|
|
+++ b/drivers/hv/dxgkrnl/Kconfig
|
|
@@ -6,6 +6,8 @@ config DXGKRNL
|
|
tristate "Microsoft Paravirtualized GPU support"
|
|
depends on HYPERV
|
|
depends on 64BIT || COMPILE_TEST
|
|
+ select DMA_SHARED_BUFFER
|
|
+ select SYNC_FILE
|
|
help
|
|
This driver supports paravirtualized virtual compute devices, exposed
|
|
by Microsoft Hyper-V when Linux is running inside of a virtual machine
|
|
diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/Makefile
|
|
+++ b/drivers/hv/dxgkrnl/Makefile
|
|
@@ -2,4 +2,4 @@
|
|
# Makefile for the hyper-v compute device driver (dxgkrnl).
|
|
|
|
obj-$(CONFIG_DXGKRNL) += dxgkrnl.o
|
|
-dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
|
|
+dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o dxgsyncfile.o
|
|
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
|
|
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
|
|
@@ -120,6 +120,7 @@ struct dxgpagingqueue {
|
|
*/
|
|
enum dxghosteventtype {
|
|
dxghostevent_cpu_event = 1,
|
|
+ dxghostevent_dma_fence = 2,
|
|
};
|
|
|
|
struct dxghostevent {
|
|
@@ -858,6 +859,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
|
|
struct
|
|
d3dkmt_waitforsynchronizationobjectfromcpu
|
|
*args,
|
|
+ bool user_address,
|
|
u64 cpu_event);
|
|
int dxgvmb_send_lock2(struct dxgprocess *process,
|
|
struct dxgadapter *adapter,
|
|
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgmodule.c
|
|
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
|
|
@@ -16,6 +16,7 @@
|
|
#include <linux/hyperv.h>
|
|
#include <linux/pci.h>
|
|
#include "dxgkrnl.h"
|
|
+#include "dxgsyncfile.h"
|
|
|
|
#define PCI_VENDOR_ID_MICROSOFT 0x1414
|
|
#define PCI_DEVICE_ID_VIRTUAL_RENDER 0x008E
|
|
@@ -145,6 +146,15 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
|
|
spin_unlock_irq(&dxgglobal->host_event_list_mutex);
|
|
}
|
|
|
|
+static void signal_dma_fence(struct dxghostevent *eventhdr)
|
|
+{
|
|
+ struct dxgsyncpoint *event = (struct dxgsyncpoint *)eventhdr;
|
|
+
|
|
+ event->fence_value++;
|
|
+ list_del(&eventhdr->host_event_list_entry);
|
|
+ dma_fence_signal(&event->base);
|
|
+}
|
|
+
|
|
void signal_host_cpu_event(struct dxghostevent *eventhdr)
|
|
{
|
|
struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
|
|
@@ -184,6 +194,8 @@ void dxgglobal_signal_host_event(u64 event_id)
|
|
DXG_TRACE("found event to signal");
|
|
if (event->event_type == dxghostevent_cpu_event)
|
|
signal_host_cpu_event(event);
|
|
+ else if (event->event_type == dxghostevent_dma_fence)
|
|
+ signal_dma_fence(event);
|
|
else
|
|
DXG_ERR("Unknown host event type");
|
|
break;
|
|
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.c b/drivers/hv/dxgkrnl/dxgsyncfile.c
|
|
new file mode 100644
|
|
index 000000000000..111111111111
|
|
--- /dev/null
|
|
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.c
|
|
@@ -0,0 +1,215 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2022, Microsoft Corporation.
|
|
+ *
|
|
+ * Author:
|
|
+ * Iouri Tarassov <iourit@linux.microsoft.com>
|
|
+ *
|
|
+ * Dxgkrnl Graphics Driver
|
|
+ * Ioctl implementation
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/eventfd.h>
|
|
+#include <linux/file.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/anon_inodes.h>
|
|
+#include <linux/mman.h>
|
|
+
|
|
+#include "dxgkrnl.h"
|
|
+#include "dxgvmbus.h"
|
|
+#include "dxgsyncfile.h"
|
|
+
|
|
+#undef dev_fmt
|
|
+#define dev_fmt(fmt) "dxgk: " fmt
|
|
+
|
|
+#ifdef DEBUG
|
|
+static char *errorstr(int ret)
|
|
+{
|
|
+ return ret < 0 ? "err" : "";
|
|
+}
|
|
+#endif
|
|
+
|
|
+static const struct dma_fence_ops dxgdmafence_ops;
|
|
+
|
|
+static struct dxgsyncpoint *to_syncpoint(struct dma_fence *fence)
|
|
+{
|
|
+ if (fence->ops != &dxgdmafence_ops)
|
|
+ return NULL;
|
|
+ return container_of(fence, struct dxgsyncpoint, base);
|
|
+}
|
|
+
|
|
+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);
|
|
+ struct sync_file *sync_file = NULL;
|
|
+ struct dxgdevice *device = NULL;
|
|
+ struct dxgadapter *adapter = NULL;
|
|
+ struct d3dkmt_waitforsynchronizationobjectfromcpu waitargs = {};
|
|
+
|
|
+ if (fd < 0) {
|
|
+ DXG_ERR("get_unused_fd_flags failed: %d", fd);
|
|
+ ret = fd;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ ret = copy_from_user(&args, inargs, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy input args");
|
|
+ ret = -EFAULT;
|
|
+ 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");
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ pt = kzalloc(sizeof(*pt), GFP_KERNEL);
|
|
+ if (!pt) {
|
|
+ ret = -ENOMEM;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ spin_lock_init(&pt->lock);
|
|
+ pt->fence_value = args.fence_value;
|
|
+ pt->context = dma_fence_context_alloc(1);
|
|
+ pt->hdr.event_id = dxgglobal_new_host_event_id();
|
|
+ pt->hdr.event_type = dxghostevent_dma_fence;
|
|
+ dxgglobal_add_host_event(&pt->hdr);
|
|
+
|
|
+ dma_fence_init(&pt->base, &dxgdmafence_ops, &pt->lock,
|
|
+ pt->context, args.fence_value);
|
|
+
|
|
+ sync_file = sync_file_create(&pt->base);
|
|
+ if (sync_file == NULL) {
|
|
+ DXG_ERR("sync_file_create failed");
|
|
+ ret = -ENOMEM;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ dma_fence_put(&pt->base);
|
|
+
|
|
+ waitargs.device = args.device;
|
|
+ waitargs.object_count = 1;
|
|
+ waitargs.objects = &args.monitored_fence;
|
|
+ waitargs.fence_values = &args.fence_value;
|
|
+ ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
|
|
+ &waitargs, false,
|
|
+ pt->hdr.event_id);
|
|
+ if (ret < 0) {
|
|
+ DXG_ERR("dxgvmb_send_wait_sync_object_cpu failed");
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ args.sync_file_handle = (u64)fd;
|
|
+ ret = copy_to_user(inargs, &args, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy output args");
|
|
+ ret = -EFAULT;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ fd_install(fd, sync_file->file);
|
|
+
|
|
+cleanup:
|
|
+ if (adapter)
|
|
+ dxgadapter_release_lock_shared(adapter);
|
|
+ if (device)
|
|
+ dxgdevice_release_lock_shared(device);
|
|
+ if (ret) {
|
|
+ if (sync_file) {
|
|
+ fput(sync_file->file);
|
|
+ /* sync_file_release will destroy dma_fence */
|
|
+ pt = NULL;
|
|
+ }
|
|
+ if (pt)
|
|
+ dma_fence_put(&pt->base);
|
|
+ if (fd >= 0)
|
|
+ put_unused_fd(fd);
|
|
+ }
|
|
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const char *dxgdmafence_get_driver_name(struct dma_fence *fence)
|
|
+{
|
|
+ return "dxgkrnl";
|
|
+}
|
|
+
|
|
+static const char *dxgdmafence_get_timeline_name(struct dma_fence *fence)
|
|
+{
|
|
+ return "no_timeline";
|
|
+}
|
|
+
|
|
+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);
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool dxgdmafence_signaled(struct dma_fence *fence)
|
|
+{
|
|
+ struct dxgsyncpoint *syncpoint;
|
|
+
|
|
+ syncpoint = to_syncpoint(fence);
|
|
+ if (syncpoint == 0)
|
|
+ return true;
|
|
+ return __dma_fence_is_later(syncpoint->fence_value, fence->seqno,
|
|
+ fence->ops);
|
|
+}
|
|
+
|
|
+static bool dxgdmafence_enable_signaling(struct dma_fence *fence)
|
|
+{
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static void dxgdmafence_value_str(struct dma_fence *fence,
|
|
+ char *str, int size)
|
|
+{
|
|
+ snprintf(str, size, "%lld", fence->seqno);
|
|
+}
|
|
+
|
|
+static void dxgdmafence_timeline_value_str(struct dma_fence *fence,
|
|
+ char *str, int size)
|
|
+{
|
|
+ struct dxgsyncpoint *syncpoint;
|
|
+
|
|
+ syncpoint = to_syncpoint(fence);
|
|
+ snprintf(str, size, "%lld", syncpoint->fence_value);
|
|
+}
|
|
+
|
|
+static const struct dma_fence_ops dxgdmafence_ops = {
|
|
+ .get_driver_name = dxgdmafence_get_driver_name,
|
|
+ .get_timeline_name = dxgdmafence_get_timeline_name,
|
|
+ .enable_signaling = dxgdmafence_enable_signaling,
|
|
+ .signaled = dxgdmafence_signaled,
|
|
+ .release = dxgdmafence_release,
|
|
+ .fence_value_str = dxgdmafence_value_str,
|
|
+ .timeline_value_str = dxgdmafence_timeline_value_str,
|
|
+};
|
|
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.h b/drivers/hv/dxgkrnl/dxgsyncfile.h
|
|
new file mode 100644
|
|
index 000000000000..111111111111
|
|
--- /dev/null
|
|
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.h
|
|
@@ -0,0 +1,30 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2022, Microsoft Corporation.
|
|
+ *
|
|
+ * Author:
|
|
+ * Iouri Tarassov <iourit@linux.microsoft.com>
|
|
+ *
|
|
+ * Dxgkrnl Graphics Driver
|
|
+ * Headers for sync file objects
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _DXGSYNCFILE_H
|
|
+#define _DXGSYNCFILE_H
|
|
+
|
|
+#include <linux/sync_file.h>
|
|
+
|
|
+int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs);
|
|
+
|
|
+struct dxgsyncpoint {
|
|
+ struct dxghostevent hdr;
|
|
+ struct dma_fence base;
|
|
+ u64 fence_value;
|
|
+ u64 context;
|
|
+ spinlock_t lock;
|
|
+ u64 u64;
|
|
+};
|
|
+
|
|
+#endif /* _DXGSYNCFILE_H */
|
|
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
|
|
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
|
|
@@ -2820,6 +2820,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
|
|
struct
|
|
d3dkmt_waitforsynchronizationobjectfromcpu
|
|
*args,
|
|
+ bool user_address,
|
|
u64 cpu_event)
|
|
{
|
|
int ret = -EINVAL;
|
|
@@ -2844,19 +2845,25 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
|
|
command->guest_event_pointer = (u64) cpu_event;
|
|
current_pos = (u8 *) &command[1];
|
|
|
|
- ret = copy_from_user(current_pos, args->objects, object_size);
|
|
- if (ret) {
|
|
- DXG_ERR("failed to copy objects");
|
|
- ret = -EINVAL;
|
|
- goto cleanup;
|
|
- }
|
|
- current_pos += object_size;
|
|
- ret = copy_from_user(current_pos, args->fence_values,
|
|
- fence_size);
|
|
- if (ret) {
|
|
- DXG_ERR("failed to copy fences");
|
|
- ret = -EINVAL;
|
|
- goto cleanup;
|
|
+ if (user_address) {
|
|
+ ret = copy_from_user(current_pos, args->objects, object_size);
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy objects");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ current_pos += object_size;
|
|
+ ret = copy_from_user(current_pos, args->fence_values,
|
|
+ fence_size);
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy fences");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ } else {
|
|
+ memcpy(current_pos, args->objects, object_size);
|
|
+ current_pos += object_size;
|
|
+ memcpy(current_pos, args->fence_values, fence_size);
|
|
}
|
|
|
|
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
|
|
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/ioctl.c
|
|
+++ b/drivers/hv/dxgkrnl/ioctl.c
|
|
@@ -19,6 +19,7 @@
|
|
|
|
#include "dxgkrnl.h"
|
|
#include "dxgvmbus.h"
|
|
+#include "dxgsyncfile.h"
|
|
|
|
#undef pr_fmt
|
|
#define pr_fmt(fmt) "dxgk: " fmt
|
|
@@ -3488,7 +3489,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
|
|
}
|
|
|
|
ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
|
|
- &args, event_id);
|
|
+ &args, true, event_id);
|
|
if (ret < 0)
|
|
goto cleanup;
|
|
|
|
@@ -5224,7 +5225,7 @@ static struct ioctl_desc ioctls[] = {
|
|
/* 0x42 */ {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE},
|
|
/* 0x43 */ {dxgkio_query_statistics, LX_DXQUERYSTATISTICS},
|
|
/* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST},
|
|
-/* 0x45 */ {},
|
|
+/* 0x45 */ {dxgkio_create_sync_file, LX_DXCREATESYNCFILE},
|
|
};
|
|
|
|
/*
|
|
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
|
|
index 111111111111..222222222222 100644
|
|
--- a/include/uapi/misc/d3dkmthk.h
|
|
+++ b/include/uapi/misc/d3dkmthk.h
|
|
@@ -1554,6 +1554,13 @@ struct d3dkmt_shareobjectwithhost {
|
|
__u64 object_vail_nt_handle;
|
|
};
|
|
|
|
+struct d3dkmt_createsyncfile {
|
|
+ struct d3dkmthandle device;
|
|
+ struct d3dkmthandle monitored_fence;
|
|
+ __u64 fence_value;
|
|
+ __u64 sync_file_handle; /* out */
|
|
+};
|
|
+
|
|
/*
|
|
* Dxgkrnl Graphics Port Driver ioctl definitions
|
|
*
|
|
@@ -1677,5 +1684,7 @@ struct d3dkmt_shareobjectwithhost {
|
|
_IOWR(0x47, 0x43, struct d3dkmt_querystatistics)
|
|
#define LX_DXSHAREOBJECTWITHHOST \
|
|
_IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost)
|
|
+#define LX_DXCREATESYNCFILE \
|
|
+ _IOWR(0x47, 0x45, struct d3dkmt_createsyncfile)
|
|
|
|
#endif /* _D3DKMTHK_H */
|
|
--
|
|
Armbian
|
|
|