Skip to content

Commit 052799b

Browse files
Iouri Tarassovchessturo
authored andcommitted
drivers: hv: dxgkrnl: Sharing of sync objects
Implement creation of a shared sync objects and the ioctl for sharing dxgsyncobject objects between processes in the virtual machine. Sync objects are shared using file descriptor (FD) handles. The name "NT handle" is used to be compatible with Windows implementation. An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The created FD handle could be sent to another process using any Linux API. To use a shared sync object in other ioctls, the object needs to be opened using its FD handle. A sync object is opened by the LX_DXOPENSYNCOBJECTFROMNTHANDLE2 ioctl, which returns a d3dkmthandle value. 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 61fda28 commit 052799b

8 files changed

Lines changed: 1181 additions & 6 deletions

File tree

drivers/hv/dxgkrnl/dxgadapter.c

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,26 @@ void dxgadapter_remove_shared_resource(struct dxgadapter *adapter,
171171
up_write(&adapter->shared_resource_list_lock);
172172
}
173173

174+
void dxgadapter_add_shared_syncobj(struct dxgadapter *adapter,
175+
struct dxgsharedsyncobject *object)
176+
{
177+
down_write(&adapter->shared_resource_list_lock);
178+
list_add_tail(&object->adapter_shared_syncobj_list_entry,
179+
&adapter->adapter_shared_syncobj_list_head);
180+
up_write(&adapter->shared_resource_list_lock);
181+
}
182+
183+
void dxgadapter_remove_shared_syncobj(struct dxgadapter *adapter,
184+
struct dxgsharedsyncobject *object)
185+
{
186+
down_write(&adapter->shared_resource_list_lock);
187+
if (object->adapter_shared_syncobj_list_entry.next) {
188+
list_del(&object->adapter_shared_syncobj_list_entry);
189+
object->adapter_shared_syncobj_list_entry.next = NULL;
190+
}
191+
up_write(&adapter->shared_resource_list_lock);
192+
}
193+
174194
void dxgadapter_add_syncobj(struct dxgadapter *adapter,
175195
struct dxgsyncobject *object)
176196
{
@@ -622,7 +642,7 @@ void dxgresource_destroy(struct dxgresource *resource)
622642
dxgallocation_destroy(alloc);
623643
}
624644
dxgdevice_remove_resource(device, resource);
625-
shared_resource = resource->shared_owner;
645+
shared_resource = resource->shared_owner;
626646
if (shared_resource) {
627647
dxgsharedresource_remove_resource(shared_resource,
628648
resource);
@@ -736,6 +756,9 @@ struct dxgcontext *dxgcontext_create(struct dxgdevice *device)
736756
*/
737757
void dxgcontext_destroy(struct dxgprocess *process, struct dxgcontext *context)
738758
{
759+
struct dxghwqueue *hwqueue;
760+
struct dxghwqueue *tmp;
761+
739762
DXG_TRACE("Destroying context %p", context);
740763
context->object_state = DXGOBJECTSTATE_DESTROYED;
741764
if (context->device) {
@@ -747,6 +770,10 @@ void dxgcontext_destroy(struct dxgprocess *process, struct dxgcontext *context)
747770
dxgdevice_remove_context(context->device, context);
748771
kref_put(&context->device->device_kref, dxgdevice_release);
749772
}
773+
list_for_each_entry_safe(hwqueue, tmp, &context->hwqueue_list_head,
774+
hwqueue_list_entry) {
775+
dxghwqueue_destroy(process, hwqueue);
776+
}
750777
kref_put(&context->context_kref, dxgcontext_release);
751778
}
752779

@@ -773,6 +800,38 @@ void dxgcontext_release(struct kref *refcount)
773800
kfree(context);
774801
}
775802

803+
int dxgcontext_add_hwqueue(struct dxgcontext *context,
804+
struct dxghwqueue *hwqueue)
805+
{
806+
int ret = 0;
807+
808+
down_write(&context->hwqueue_list_lock);
809+
if (dxgcontext_is_active(context))
810+
list_add_tail(&hwqueue->hwqueue_list_entry,
811+
&context->hwqueue_list_head);
812+
else
813+
ret = -ENODEV;
814+
up_write(&context->hwqueue_list_lock);
815+
return ret;
816+
}
817+
818+
void dxgcontext_remove_hwqueue(struct dxgcontext *context,
819+
struct dxghwqueue *hwqueue)
820+
{
821+
if (hwqueue->hwqueue_list_entry.next) {
822+
list_del(&hwqueue->hwqueue_list_entry);
823+
hwqueue->hwqueue_list_entry.next = NULL;
824+
}
825+
}
826+
827+
void dxgcontext_remove_hwqueue_safe(struct dxgcontext *context,
828+
struct dxghwqueue *hwqueue)
829+
{
830+
down_write(&context->hwqueue_list_lock);
831+
dxgcontext_remove_hwqueue(context, hwqueue);
832+
up_write(&context->hwqueue_list_lock);
833+
}
834+
776835
struct dxgallocation *dxgallocation_create(struct dxgprocess *process)
777836
{
778837
struct dxgallocation *alloc;
@@ -958,6 +1017,63 @@ void dxgprocess_adapter_remove_device(struct dxgdevice *device)
9581017
mutex_unlock(&device->adapter_info->device_list_mutex);
9591018
}
9601019

1020+
struct dxgsharedsyncobject *dxgsharedsyncobj_create(struct dxgadapter *adapter,
1021+
struct dxgsyncobject *so)
1022+
{
1023+
struct dxgsharedsyncobject *syncobj;
1024+
1025+
syncobj = kzalloc(sizeof(*syncobj), GFP_KERNEL);
1026+
if (syncobj) {
1027+
kref_init(&syncobj->ssyncobj_kref);
1028+
INIT_LIST_HEAD(&syncobj->shared_syncobj_list_head);
1029+
syncobj->adapter = adapter;
1030+
syncobj->type = so->type;
1031+
syncobj->monitored_fence = so->monitored_fence;
1032+
dxgadapter_add_shared_syncobj(adapter, syncobj);
1033+
kref_get(&adapter->adapter_kref);
1034+
init_rwsem(&syncobj->syncobj_list_lock);
1035+
mutex_init(&syncobj->fd_mutex);
1036+
}
1037+
return syncobj;
1038+
}
1039+
1040+
void dxgsharedsyncobj_release(struct kref *refcount)
1041+
{
1042+
struct dxgsharedsyncobject *syncobj;
1043+
1044+
syncobj = container_of(refcount, struct dxgsharedsyncobject,
1045+
ssyncobj_kref);
1046+
DXG_TRACE("Destroying shared sync object %p", syncobj);
1047+
if (syncobj->adapter) {
1048+
dxgadapter_remove_shared_syncobj(syncobj->adapter,
1049+
syncobj);
1050+
kref_put(&syncobj->adapter->adapter_kref,
1051+
dxgadapter_release);
1052+
}
1053+
kfree(syncobj);
1054+
}
1055+
1056+
void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *shared,
1057+
struct dxgsyncobject *syncobj)
1058+
{
1059+
DXG_TRACE("Add syncobj 0x%p 0x%p", shared, syncobj);
1060+
kref_get(&shared->ssyncobj_kref);
1061+
down_write(&shared->syncobj_list_lock);
1062+
list_add(&syncobj->shared_syncobj_list_entry,
1063+
&shared->shared_syncobj_list_head);
1064+
syncobj->shared_owner = shared;
1065+
up_write(&shared->syncobj_list_lock);
1066+
}
1067+
1068+
void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *shared,
1069+
struct dxgsyncobject *syncobj)
1070+
{
1071+
DXG_TRACE("Remove syncobj 0x%p", shared);
1072+
down_write(&shared->syncobj_list_lock);
1073+
list_del(&syncobj->shared_syncobj_list_entry);
1074+
up_write(&shared->syncobj_list_lock);
1075+
}
1076+
9611077
struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
9621078
struct dxgdevice *device,
9631079
struct dxgadapter *adapter,
@@ -1091,7 +1207,70 @@ void dxgsyncobject_release(struct kref *refcount)
10911207
struct dxgsyncobject *syncobj;
10921208

10931209
syncobj = container_of(refcount, struct dxgsyncobject, syncobj_kref);
1210+
if (syncobj->shared_owner) {
1211+
dxgsharedsyncobj_remove_syncobj(syncobj->shared_owner,
1212+
syncobj);
1213+
kref_put(&syncobj->shared_owner->ssyncobj_kref,
1214+
dxgsharedsyncobj_release);
1215+
}
10941216
if (syncobj->host_event)
10951217
kfree(syncobj->host_event);
10961218
kfree(syncobj);
10971219
}
1220+
1221+
struct dxghwqueue *dxghwqueue_create(struct dxgcontext *context)
1222+
{
1223+
struct dxgprocess *process = context->device->process;
1224+
struct dxghwqueue *hwqueue = kzalloc(sizeof(*hwqueue), GFP_KERNEL);
1225+
1226+
if (hwqueue) {
1227+
kref_init(&hwqueue->hwqueue_kref);
1228+
hwqueue->context = context;
1229+
hwqueue->process = process;
1230+
hwqueue->device_handle = context->device->handle;
1231+
if (dxgcontext_add_hwqueue(context, hwqueue) < 0) {
1232+
kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release);
1233+
hwqueue = NULL;
1234+
} else {
1235+
kref_get(&context->context_kref);
1236+
}
1237+
}
1238+
return hwqueue;
1239+
}
1240+
1241+
void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwqueue)
1242+
{
1243+
DXG_TRACE("Destroyng hwqueue %p", hwqueue);
1244+
hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
1245+
if (hwqueue->handle.v) {
1246+
hmgrtable_free_handle(&process->handle_table,
1247+
HMGRENTRY_TYPE_DXGHWQUEUE,
1248+
hwqueue->handle);
1249+
hwqueue->handle.v = 0;
1250+
}
1251+
if (hwqueue->progress_fence_sync_object.v) {
1252+
hmgrtable_free_handle(&process->handle_table,
1253+
HMGRENTRY_TYPE_MONITOREDFENCE,
1254+
hwqueue->progress_fence_sync_object);
1255+
hwqueue->progress_fence_sync_object.v = 0;
1256+
}
1257+
hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
1258+
1259+
if (hwqueue->progress_fence_mapped_address) {
1260+
dxg_unmap_iospace(hwqueue->progress_fence_mapped_address,
1261+
PAGE_SIZE);
1262+
hwqueue->progress_fence_mapped_address = NULL;
1263+
}
1264+
dxgcontext_remove_hwqueue_safe(hwqueue->context, hwqueue);
1265+
1266+
kref_put(&hwqueue->context->context_kref, dxgcontext_release);
1267+
kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release);
1268+
}
1269+
1270+
void dxghwqueue_release(struct kref *refcount)
1271+
{
1272+
struct dxghwqueue *hwqueue;
1273+
1274+
hwqueue = container_of(refcount, struct dxghwqueue, hwqueue_kref);
1275+
kfree(hwqueue);
1276+
}

drivers/hv/dxgkrnl/dxgkrnl.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct dxgallocation;
4040
struct dxgresource;
4141
struct dxgsharedresource;
4242
struct dxgsyncobject;
43+
struct dxgsharedsyncobject;
44+
struct dxghwqueue;
4345

4446
/*
4547
* Driver private data.
@@ -137,6 +139,18 @@ struct dxghosteventcpu {
137139
* "device" syncobject, because the belong to a device (dxgdevice).
138140
* Device syncobjects are inserted to a list in dxgdevice.
139141
*
142+
* A syncobject can be "shared", meaning that it could be opened by many
143+
* processes.
144+
*
145+
* Shared syncobjects are inserted to a list in its owner
146+
* (dxgsharedsyncobject).
147+
* A syncobject can be shared by using a global handle or by using
148+
* "NT security handle".
149+
* When global handle sharing is used, the handle is created durinig object
150+
* creation.
151+
* When "NT security" is used, the handle for sharing is create be calling
152+
* dxgk_share_objects. On Linux "NT handle" is represented by a file
153+
* descriptor. FD points to dxgsharedsyncobject.
140154
*/
141155
struct dxgsyncobject {
142156
struct kref syncobj_kref;
@@ -146,6 +160,8 @@ struct dxgsyncobject {
146160
* List entry in dxgadapter for other objects
147161
*/
148162
struct list_head syncobj_list_entry;
163+
/* List entry in the dxgsharedsyncobject object for shared synobjects */
164+
struct list_head shared_syncobj_list_entry;
149165
/* Adapter, the syncobject belongs to. NULL for stopped sync obejcts. */
150166
struct dxgadapter *adapter;
151167
/*
@@ -156,6 +172,8 @@ struct dxgsyncobject {
156172
struct dxgprocess *process;
157173
/* Used by D3DDDI_CPU_NOTIFICATION objects */
158174
struct dxghosteventcpu *host_event;
175+
/* Owner object for shared syncobjects */
176+
struct dxgsharedsyncobject *shared_owner;
159177
/* CPU virtual address of the fence value for "device" syncobjects */
160178
void *mapped_address;
161179
/* Handle in the process handle table */
@@ -187,6 +205,41 @@ struct dxgvgpuchannel {
187205
struct hv_device *hdev;
188206
};
189207

208+
/*
209+
* The object is used as parent of all sync objects, created for a shared
210+
* syncobject. When a shared syncobject is created without NT security, the
211+
* handle in the global handle table will point to this object.
212+
*/
213+
struct dxgsharedsyncobject {
214+
struct kref ssyncobj_kref;
215+
/* Referenced by file descriptors */
216+
int host_shared_handle_nt_reference;
217+
/* Corresponding handle in the host global handle table */
218+
struct d3dkmthandle host_shared_handle;
219+
/*
220+
* When the sync object is shared by NT handle, this is the
221+
* corresponding handle in the host
222+
*/
223+
struct d3dkmthandle host_shared_handle_nt;
224+
/* Protects access to host_shared_handle_nt */
225+
struct mutex fd_mutex;
226+
struct rw_semaphore syncobj_list_lock;
227+
struct list_head shared_syncobj_list_head;
228+
struct list_head adapter_shared_syncobj_list_entry;
229+
struct dxgadapter *adapter;
230+
enum d3dddi_synchronizationobject_type type;
231+
u32 monitored_fence:1;
232+
};
233+
234+
struct dxgsharedsyncobject *dxgsharedsyncobj_create(struct dxgadapter *adapter,
235+
struct dxgsyncobject
236+
*syncobj);
237+
void dxgsharedsyncobj_release(struct kref *refcount);
238+
void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *sharedsyncobj,
239+
struct dxgsyncobject *syncobj);
240+
void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *sharedsyncobj,
241+
struct dxgsyncobject *syncobj);
242+
190243
struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
191244
struct dxgdevice *device,
192245
struct dxgadapter *adapter,
@@ -375,6 +428,8 @@ struct dxgadapter {
375428
struct list_head adapter_process_list_head;
376429
/* List of all dxgsharedresource objects */
377430
struct list_head shared_resource_list_head;
431+
/* List of all dxgsharedsyncobject objects */
432+
struct list_head adapter_shared_syncobj_list_head;
378433
/* List of all non-device dxgsyncobject objects */
379434
struct list_head syncobj_list_head;
380435
/* This lock protects shared resource and syncobject lists */
@@ -402,6 +457,10 @@ void dxgadapter_release_lock_shared(struct dxgadapter *adapter);
402457
int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter);
403458
void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter);
404459
void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter);
460+
void dxgadapter_add_shared_syncobj(struct dxgadapter *adapter,
461+
struct dxgsharedsyncobject *so);
462+
void dxgadapter_remove_shared_syncobj(struct dxgadapter *adapter,
463+
struct dxgsharedsyncobject *so);
405464
void dxgadapter_add_syncobj(struct dxgadapter *adapter,
406465
struct dxgsyncobject *so);
407466
void dxgadapter_remove_syncobj(struct dxgsyncobject *so);
@@ -487,8 +546,32 @@ struct dxgcontext *dxgcontext_create(struct dxgdevice *dev);
487546
void dxgcontext_destroy(struct dxgprocess *pr, struct dxgcontext *ctx);
488547
void dxgcontext_destroy_safe(struct dxgprocess *pr, struct dxgcontext *ctx);
489548
void dxgcontext_release(struct kref *refcount);
549+
int dxgcontext_add_hwqueue(struct dxgcontext *ctx,
550+
struct dxghwqueue *hq);
551+
void dxgcontext_remove_hwqueue(struct dxgcontext *ctx, struct dxghwqueue *hq);
552+
void dxgcontext_remove_hwqueue_safe(struct dxgcontext *ctx,
553+
struct dxghwqueue *hq);
490554
bool dxgcontext_is_active(struct dxgcontext *ctx);
491555

556+
/*
557+
* The object represent the execution hardware queue of a device.
558+
*/
559+
struct dxghwqueue {
560+
/* entry in the context hw queue list */
561+
struct list_head hwqueue_list_entry;
562+
struct kref hwqueue_kref;
563+
struct dxgcontext *context;
564+
struct dxgprocess *process;
565+
struct d3dkmthandle progress_fence_sync_object;
566+
struct d3dkmthandle handle;
567+
struct d3dkmthandle device_handle;
568+
void *progress_fence_mapped_address;
569+
};
570+
571+
struct dxghwqueue *dxghwqueue_create(struct dxgcontext *ctx);
572+
void dxghwqueue_destroy(struct dxgprocess *pr, struct dxghwqueue *hq);
573+
void dxghwqueue_release(struct kref *refcount);
574+
492575
/*
493576
* A shared resource object is created to track the list of dxgresource objects,
494577
* which are opened for the same underlying shared resource.
@@ -720,9 +803,22 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
720803
d3dkmt_waitforsynchronizationobjectfromcpu
721804
*args,
722805
u64 cpu_event);
806+
int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
807+
struct dxgadapter *adapter,
808+
struct d3dkmt_createhwqueue *args,
809+
struct d3dkmt_createhwqueue *__user inargs,
810+
struct dxghwqueue *hq);
811+
int dxgvmb_send_destroy_hwqueue(struct dxgprocess *process,
812+
struct dxgadapter *adapter,
813+
struct d3dkmthandle handle);
723814
int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
724815
struct dxgadapter *adapter,
725816
struct d3dkmt_queryadapterinfo *args);
817+
int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process,
818+
struct dxgvmbuschannel *channel,
819+
struct d3dkmt_opensyncobjectfromnthandle2
820+
*args,
821+
struct dxgsyncobject *syncobj);
726822
int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process,
727823
struct d3dkmthandle object,
728824
struct d3dkmthandle *shared_handle);

0 commit comments

Comments
 (0)