Skip to content

Commit 033834b

Browse files
author
Iouri Tarassov
committed
drivers: hv: dxgkrnl: Implement DXGSYNCFILE
Signed-off-by: Iouri Tarassov <[email protected]>
1 parent 0f18a58 commit 033834b

File tree

11 files changed

+299
-21
lines changed

11 files changed

+299
-21
lines changed

drivers/hv/dxgkrnl/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
config DXGKRNL
66
tristate "Microsoft Paravirtualized GPU support"
77
depends on HYPERV
8+
select DMA_SHARED_BUFFER
9+
select SYNC_FILE
810
help
911
This driver supports paravirtualized virtual GPU devices, exposed by
1012
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)