Skip to content

Commit 17b01f5

Browse files
Iouri Tarassovchessturo
authored andcommitted
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 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
1 parent bdd7ff7 commit 17b01f5

9 files changed

Lines changed: 294 additions & 16 deletions

File tree

drivers/hv/dxgkrnl/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ config DXGKRNL
66
tristate "Microsoft Paravirtualized GPU support"
77
depends on HYPERV
88
depends on 64BIT || COMPILE_TEST
9+
select DMA_SHARED_BUFFER
10+
select SYNC_FILE
911
help
1012
This driver supports paravirtualized virtual compute devices, exposed
1113
by Microsoft Hyper-V when Linux is running inside of a virtual machine

drivers/hv/dxgkrnl/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Makefile for the hyper-v compute device driver (dxgkrnl).
33

44
obj-$(CONFIG_DXGKRNL) += dxgkrnl.o
5-
dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
5+
dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o dxgsyncfile.o

drivers/hv/dxgkrnl/dxgkrnl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ struct dxgpagingqueue {
120120
*/
121121
enum dxghosteventtype {
122122
dxghostevent_cpu_event = 1,
123+
dxghostevent_dma_fence = 2,
123124
};
124125

125126
struct dxghostevent {
@@ -858,6 +859,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
858859
struct
859860
d3dkmt_waitforsynchronizationobjectfromcpu
860861
*args,
862+
bool user_address,
861863
u64 cpu_event);
862864
int dxgvmb_send_lock2(struct dxgprocess *process,
863865
struct dxgadapter *adapter,

drivers/hv/dxgkrnl/dxgmodule.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/hyperv.h>
1717
#include <linux/pci.h>
1818
#include "dxgkrnl.h"
19+
#include "dxgsyncfile.h"
1920

2021
#define PCI_VENDOR_ID_MICROSOFT 0x1414
2122
#define PCI_DEVICE_ID_VIRTUAL_RENDER 0x008E
@@ -145,6 +146,15 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
145146
spin_unlock_irq(&dxgglobal->host_event_list_mutex);
146147
}
147148

149+
static void signal_dma_fence(struct dxghostevent *eventhdr)
150+
{
151+
struct dxgsyncpoint *event = (struct dxgsyncpoint *)eventhdr;
152+
153+
event->fence_value++;
154+
list_del(&eventhdr->host_event_list_entry);
155+
dma_fence_signal(&event->base);
156+
}
157+
148158
void signal_host_cpu_event(struct dxghostevent *eventhdr)
149159
{
150160
struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
@@ -184,6 +194,8 @@ void dxgglobal_signal_host_event(u64 event_id)
184194
DXG_TRACE("found event to signal");
185195
if (event->event_type == dxghostevent_cpu_event)
186196
signal_host_cpu_event(event);
197+
else if (event->event_type == dxghostevent_dma_fence)
198+
signal_dma_fence(event);
187199
else
188200
DXG_ERR("Unknown host event type");
189201
break;

drivers/hv/dxgkrnl/dxgsyncfile.c

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
/*
4+
* Copyright (c) 2022, Microsoft Corporation.
5+
*
6+
* Author:
7+
* Iouri Tarassov <iourit@linux.microsoft.com>
8+
*
9+
* Dxgkrnl Graphics Driver
10+
* Ioctl implementation
11+
*
12+
*/
13+
14+
#include <linux/eventfd.h>
15+
#include <linux/file.h>
16+
#include <linux/fs.h>
17+
#include <linux/anon_inodes.h>
18+
#include <linux/mman.h>
19+
20+
#include "dxgkrnl.h"
21+
#include "dxgvmbus.h"
22+
#include "dxgsyncfile.h"
23+
24+
#undef dev_fmt
25+
#define dev_fmt(fmt) "dxgk: " fmt
26+
27+
#ifdef DEBUG
28+
static char *errorstr(int ret)
29+
{
30+
return ret < 0 ? "err" : "";
31+
}
32+
#endif
33+
34+
static const struct dma_fence_ops dxgdmafence_ops;
35+
36+
static struct dxgsyncpoint *to_syncpoint(struct dma_fence *fence)
37+
{
38+
if (fence->ops != &dxgdmafence_ops)
39+
return NULL;
40+
return container_of(fence, struct dxgsyncpoint, base);
41+
}
42+
43+
int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
44+
{
45+
struct d3dkmt_createsyncfile args;
46+
struct dxgsyncpoint *pt = NULL;
47+
int ret = 0;
48+
int fd = get_unused_fd_flags(O_CLOEXEC);
49+
struct sync_file *sync_file = NULL;
50+
struct dxgdevice *device = NULL;
51+
struct dxgadapter *adapter = NULL;
52+
struct d3dkmt_waitforsynchronizationobjectfromcpu waitargs = {};
53+
54+
if (fd < 0) {
55+
DXG_ERR("get_unused_fd_flags failed: %d", fd);
56+
ret = fd;
57+
goto cleanup;
58+
}
59+
60+
ret = copy_from_user(&args, inargs, sizeof(args));
61+
if (ret) {
62+
DXG_ERR("failed to copy input args");
63+
ret = -EFAULT;
64+
goto cleanup;
65+
}
66+
67+
device = dxgprocess_device_by_handle(process, args.device);
68+
if (device == NULL) {
69+
DXG_ERR("dxgprocess_device_by_handle failed");
70+
ret = -EINVAL;
71+
goto cleanup;
72+
}
73+
74+
ret = dxgdevice_acquire_lock_shared(device);
75+
if (ret < 0) {
76+
DXG_ERR("dxgdevice_acquire_lock_shared failed");
77+
device = NULL;
78+
goto cleanup;
79+
}
80+
81+
adapter = device->adapter;
82+
ret = dxgadapter_acquire_lock_shared(adapter);
83+
if (ret < 0) {
84+
DXG_ERR("dxgadapter_acquire_lock_shared failed");
85+
adapter = NULL;
86+
goto cleanup;
87+
}
88+
89+
pt = kzalloc(sizeof(*pt), GFP_KERNEL);
90+
if (!pt) {
91+
ret = -ENOMEM;
92+
goto cleanup;
93+
}
94+
spin_lock_init(&pt->lock);
95+
pt->fence_value = args.fence_value;
96+
pt->context = dma_fence_context_alloc(1);
97+
pt->hdr.event_id = dxgglobal_new_host_event_id();
98+
pt->hdr.event_type = dxghostevent_dma_fence;
99+
dxgglobal_add_host_event(&pt->hdr);
100+
101+
dma_fence_init(&pt->base, &dxgdmafence_ops, &pt->lock,
102+
pt->context, args.fence_value);
103+
104+
sync_file = sync_file_create(&pt->base);
105+
if (sync_file == NULL) {
106+
DXG_ERR("sync_file_create failed");
107+
ret = -ENOMEM;
108+
goto cleanup;
109+
}
110+
dma_fence_put(&pt->base);
111+
112+
waitargs.device = args.device;
113+
waitargs.object_count = 1;
114+
waitargs.objects = &args.monitored_fence;
115+
waitargs.fence_values = &args.fence_value;
116+
ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
117+
&waitargs, false,
118+
pt->hdr.event_id);
119+
if (ret < 0) {
120+
DXG_ERR("dxgvmb_send_wait_sync_object_cpu failed");
121+
goto cleanup;
122+
}
123+
124+
args.sync_file_handle = (u64)fd;
125+
ret = copy_to_user(inargs, &args, sizeof(args));
126+
if (ret) {
127+
DXG_ERR("failed to copy output args");
128+
ret = -EFAULT;
129+
goto cleanup;
130+
}
131+
132+
fd_install(fd, sync_file->file);
133+
134+
cleanup:
135+
if (adapter)
136+
dxgadapter_release_lock_shared(adapter);
137+
if (device)
138+
dxgdevice_release_lock_shared(device);
139+
if (ret) {
140+
if (sync_file) {
141+
fput(sync_file->file);
142+
/* sync_file_release will destroy dma_fence */
143+
pt = NULL;
144+
}
145+
if (pt)
146+
dma_fence_put(&pt->base);
147+
if (fd >= 0)
148+
put_unused_fd(fd);
149+
}
150+
DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
151+
return ret;
152+
}
153+
154+
static const char *dxgdmafence_get_driver_name(struct dma_fence *fence)
155+
{
156+
return "dxgkrnl";
157+
}
158+
159+
static const char *dxgdmafence_get_timeline_name(struct dma_fence *fence)
160+
{
161+
return "no_timeline";
162+
}
163+
164+
static void dxgdmafence_release(struct dma_fence *fence)
165+
{
166+
struct dxgsyncpoint *syncpoint;
167+
168+
syncpoint = to_syncpoint(fence);
169+
if (syncpoint) {
170+
if (syncpoint->hdr.event_id)
171+
dxgglobal_get_host_event(syncpoint->hdr.event_id);
172+
kfree(syncpoint);
173+
}
174+
}
175+
176+
static bool dxgdmafence_signaled(struct dma_fence *fence)
177+
{
178+
struct dxgsyncpoint *syncpoint;
179+
180+
syncpoint = to_syncpoint(fence);
181+
if (syncpoint == 0)
182+
return true;
183+
return __dma_fence_is_later(syncpoint->fence_value, fence->seqno,
184+
fence->ops);
185+
}
186+
187+
static bool dxgdmafence_enable_signaling(struct dma_fence *fence)
188+
{
189+
return true;
190+
}
191+
192+
static void dxgdmafence_value_str(struct dma_fence *fence,
193+
char *str, int size)
194+
{
195+
snprintf(str, size, "%lld", fence->seqno);
196+
}
197+
198+
static void dxgdmafence_timeline_value_str(struct dma_fence *fence,
199+
char *str, int size)
200+
{
201+
struct dxgsyncpoint *syncpoint;
202+
203+
syncpoint = to_syncpoint(fence);
204+
snprintf(str, size, "%lld", syncpoint->fence_value);
205+
}
206+
207+
static const struct dma_fence_ops dxgdmafence_ops = {
208+
.get_driver_name = dxgdmafence_get_driver_name,
209+
.get_timeline_name = dxgdmafence_get_timeline_name,
210+
.enable_signaling = dxgdmafence_enable_signaling,
211+
.signaled = dxgdmafence_signaled,
212+
.release = dxgdmafence_release,
213+
.fence_value_str = dxgdmafence_value_str,
214+
.timeline_value_str = dxgdmafence_timeline_value_str,
215+
};

drivers/hv/dxgkrnl/dxgsyncfile.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
/*
4+
* Copyright (c) 2022, Microsoft Corporation.
5+
*
6+
* Author:
7+
* Iouri Tarassov <iourit@linux.microsoft.com>
8+
*
9+
* Dxgkrnl Graphics Driver
10+
* Headers for sync file objects
11+
*
12+
*/
13+
14+
#ifndef _DXGSYNCFILE_H
15+
#define _DXGSYNCFILE_H
16+
17+
#include <linux/sync_file.h>
18+
19+
int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs);
20+
21+
struct dxgsyncpoint {
22+
struct dxghostevent hdr;
23+
struct dma_fence base;
24+
u64 fence_value;
25+
u64 context;
26+
spinlock_t lock;
27+
u64 u64;
28+
};
29+
30+
#endif /* _DXGSYNCFILE_H */

drivers/hv/dxgkrnl/dxgvmbus.c

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2820,6 +2820,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
28202820
struct
28212821
d3dkmt_waitforsynchronizationobjectfromcpu
28222822
*args,
2823+
bool user_address,
28232824
u64 cpu_event)
28242825
{
28252826
int ret = -EINVAL;
@@ -2844,19 +2845,25 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
28442845
command->guest_event_pointer = (u64) cpu_event;
28452846
current_pos = (u8 *) &command[1];
28462847

2847-
ret = copy_from_user(current_pos, args->objects, object_size);
2848-
if (ret) {
2849-
DXG_ERR("failed to copy objects");
2850-
ret = -EINVAL;
2851-
goto cleanup;
2852-
}
2853-
current_pos += object_size;
2854-
ret = copy_from_user(current_pos, args->fence_values,
2855-
fence_size);
2856-
if (ret) {
2857-
DXG_ERR("failed to copy fences");
2858-
ret = -EINVAL;
2859-
goto cleanup;
2848+
if (user_address) {
2849+
ret = copy_from_user(current_pos, args->objects, object_size);
2850+
if (ret) {
2851+
DXG_ERR("failed to copy objects");
2852+
ret = -EINVAL;
2853+
goto cleanup;
2854+
}
2855+
current_pos += object_size;
2856+
ret = copy_from_user(current_pos, args->fence_values,
2857+
fence_size);
2858+
if (ret) {
2859+
DXG_ERR("failed to copy fences");
2860+
ret = -EINVAL;
2861+
goto cleanup;
2862+
}
2863+
} else {
2864+
memcpy(current_pos, args->objects, object_size);
2865+
current_pos += object_size;
2866+
memcpy(current_pos, args->fence_values, fence_size);
28602867
}
28612868

28622869
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);

drivers/hv/dxgkrnl/ioctl.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "dxgkrnl.h"
2121
#include "dxgvmbus.h"
22+
#include "dxgsyncfile.h"
2223

2324
#undef pr_fmt
2425
#define pr_fmt(fmt) "dxgk: " fmt
@@ -3488,7 +3489,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
34883489
}
34893490

34903491
ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
3491-
&args, event_id);
3492+
&args, true, event_id);
34923493
if (ret < 0)
34933494
goto cleanup;
34943495

@@ -5224,7 +5225,7 @@ static struct ioctl_desc ioctls[] = {
52245225
/* 0x42 */ {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE},
52255226
/* 0x43 */ {dxgkio_query_statistics, LX_DXQUERYSTATISTICS},
52265227
/* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST},
5227-
/* 0x45 */ {},
5228+
/* 0x45 */ {dxgkio_create_sync_file, LX_DXCREATESYNCFILE},
52285229
};
52295230

52305231
/*

0 commit comments

Comments
 (0)