Skip to content

Commit 606198e

Browse files
author
Iouri Tarassov
committed
drivers: hv: dxgkrnl: Implement DXGSYNCFILE
Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile). 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 sync_object file descriptor is returned to the caller. The caller could wait for the object by using poll(). When the 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 <[email protected]>
1 parent 51e80c0 commit 606198e

File tree

10 files changed

+289
-20
lines changed

10 files changed

+289
-20
lines changed

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 Linux video drivers.
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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
828828
struct
829829
d3dkmt_waitforsynchronizationobjectfromcpu
830830
*args,
831+
bool user_address,
831832
u64 cpu_event);
832833
int dxgvmb_send_lock2(struct dxgprocess *process,
833834
struct dxgadapter *adapter,

drivers/hv/dxgkrnl/dxgmodule.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
#include <linux/eventfd.h>
1616
#include <linux/hyperv.h>
1717
#include <linux/pci.h>
18+
#include <linux/sync_file.h>
1819

1920
#include "dxgkrnl.h"
21+
#include "dxgsyncfile.h"
2022

2123
struct dxgglobal *dxgglobal;
2224
struct device *dxgglobaldev;
@@ -134,7 +136,7 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
134136

135137
void signal_host_cpu_event(struct dxghostevent *eventhdr)
136138
{
137-
struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
139+
struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
138140

139141
if (event->remove_from_list ||
140142
event->destroy_after_signal) {
@@ -157,6 +159,15 @@ void signal_host_cpu_event(struct dxghostevent *eventhdr)
157159
}
158160
}
159161

162+
void signal_dma_fence(struct dxghostevent *eventhdr)
163+
{
164+
struct dxgsyncpoint *event = (struct dxgsyncpoint *)eventhdr;
165+
166+
event->fence_value++;
167+
list_del(&eventhdr->host_event_list_entry);
168+
dma_fence_signal(&event->base);
169+
}
170+
160171
void dxgglobal_signal_host_event(u64 event_id)
161172
{
162173
struct dxghostevent *event;
@@ -172,6 +183,8 @@ void dxgglobal_signal_host_event(u64 event_id)
172183
event_id);
173184
if (event->event_type == dxghostevent_cpu_event)
174185
signal_host_cpu_event(event);
186+
else if (event->event_type == dxghostevent_dma_fence)
187+
signal_dma_fence(event);
175188
else
176189
pr_err("Unknown host event type");
177190
break;

drivers/hv/dxgkrnl/dxgsyncfile.c

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

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) 2019, Microsoft Corporation.
5+
*
6+
* Author:
7+
* Iouri Tarassov <[email protected]>
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 dxgk_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 & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2681,6 +2681,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
26812681
struct
26822682
d3dkmt_waitforsynchronizationobjectfromcpu
26832683
*args,
2684+
bool user_address,
26842685
u64 cpu_event)
26852686
{
26862687
int ret = -EINVAL;
@@ -2704,18 +2705,25 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
27042705
command->object_count = args->object_count;
27052706
command->guest_event_pointer = (u64) cpu_event;
27062707
current_pos = (u8 *) &command[1];
2707-
ret = copy_from_user(current_pos, args->objects, object_size);
2708-
if (ret) {
2709-
pr_err("%s failed to copy objects", __func__);
2710-
ret = -EINVAL;
2711-
goto cleanup;
2712-
}
2713-
current_pos += object_size;
2714-
ret = copy_from_user(current_pos, args->fence_values, fence_size);
2715-
if (ret) {
2716-
pr_err("%s failed to copy fences", __func__);
2717-
ret = -EINVAL;
2718-
goto cleanup;
2708+
if (user_address) {
2709+
ret = copy_from_user(current_pos, args->objects, object_size);
2710+
if (ret) {
2711+
pr_err("%s failed to copy objects", __func__);
2712+
ret = -EINVAL;
2713+
goto cleanup;
2714+
}
2715+
current_pos += object_size;
2716+
ret = copy_from_user(current_pos, args->fence_values,
2717+
fence_size);
2718+
if (ret) {
2719+
pr_err("%s failed to copy fences", __func__);
2720+
ret = -EINVAL;
2721+
goto cleanup;
2722+
}
2723+
} else {
2724+
memcpy(current_pos, args->objects, object_size);
2725+
current_pos += object_size;
2726+
memcpy(current_pos, args->fence_values, fence_size);
27192727
}
27202728

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

drivers/hv/dxgkrnl/ioctl.c

Lines changed: 4 additions & 6 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:err: " fmt
@@ -32,11 +33,6 @@ struct ioctl_desc {
3233
};
3334
static struct ioctl_desc ioctls[LX_IO_MAX + 1];
3435

35-
static char *errorstr(int ret)
36-
{
37-
return ret < 0 ? "err" : "";
38-
}
39-
4036
static int dxgsyncobj_release(struct inode *inode, struct file *file)
4137
{
4238
struct dxgsharedsyncobject *syncobj = file->private_data;
@@ -3561,7 +3557,7 @@ dxgk_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
35613557
}
35623558

35633559
ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
3564-
&args, event_id);
3560+
&args, true, event_id);
35653561
if (ret < 0)
35663562
goto cleanup;
35673563

@@ -5556,4 +5552,6 @@ void init_ioctls(void)
55565552
LX_DXQUERYSTATISTICS);
55575553
SET_IOCTL(/*0x44 */ dxgk_share_object_with_host,
55585554
LX_DXSHAREOBJECTWITHHOST);
5555+
SET_IOCTL(/*0x45 */ dxgk_create_sync_file,
5556+
LX_DXCREATESYNCFILE);
55595557
}

0 commit comments

Comments
 (0)