Skip to content

Commit 6d6faa2

Browse files
Iouri Tarassovchessturo
authored andcommitted
drivers: hv: dxgkrnl: Creation of compute device sync objects
Implement ioctls to create and destroy compute devicesync objects: - the LX_DXCREATESYNCHRONIZATIONOBJECT ioctl, - the LX_DXDESTROYSYNCHRONIZATIONOBJECT ioctl. Compute device synchronization objects are used to synchronize execution of compute device commands, which are queued to different execution contexts (dxgcontext objects). There are several types of sync objects (mutex, monitored fence, CPU event, fence). A "signal" or a "wait" operation could be queued to an execution context. Monitored fence sync objects are particular important. A monitored fence object has a fence value, which could be monitored by the compute device or by CPU. Therefore, a CPU virtual address is allocated during object creation to allow an application to read the fence value. dxg_map_iospace and dxg_unmap_iospace implement creation of the CPU virtual address. This is done as follow: - The host allocates a portion of the guest IO space, which is mapped to the actual fence value memory on the host - The host returns the guest IO space address to the guest - The guest allocates a CPU virtual address and updates page tables to point to the IO space address 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 2dd1d57 commit 6d6faa2

8 files changed

Lines changed: 729 additions & 2 deletions

File tree

drivers/hv/dxgkrnl/dxgadapter.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,24 @@ void dxgadapter_remove_process(struct dxgprocess_adapter *process_info)
160160
list_del(&process_info->adapter_process_list_entry);
161161
}
162162

163+
void dxgadapter_add_syncobj(struct dxgadapter *adapter,
164+
struct dxgsyncobject *object)
165+
{
166+
down_write(&adapter->shared_resource_list_lock);
167+
list_add_tail(&object->syncobj_list_entry, &adapter->syncobj_list_head);
168+
up_write(&adapter->shared_resource_list_lock);
169+
}
170+
171+
void dxgadapter_remove_syncobj(struct dxgsyncobject *object)
172+
{
173+
down_write(&object->adapter->shared_resource_list_lock);
174+
if (object->syncobj_list_entry.next) {
175+
list_del(&object->syncobj_list_entry);
176+
object->syncobj_list_entry.next = NULL;
177+
}
178+
up_write(&object->adapter->shared_resource_list_lock);
179+
}
180+
163181
int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter)
164182
{
165183
down_write(&adapter->core_lock);
@@ -213,6 +231,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
213231
init_rwsem(&device->context_list_lock);
214232
init_rwsem(&device->alloc_list_lock);
215233
INIT_LIST_HEAD(&device->pqueue_list_head);
234+
INIT_LIST_HEAD(&device->syncobj_list_head);
216235
device->object_state = DXGOBJECTSTATE_CREATED;
217236
device->execution_state = _D3DKMT_DEVICEEXECUTION_ACTIVE;
218237

@@ -228,13 +247,22 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
228247
void dxgdevice_stop(struct dxgdevice *device)
229248
{
230249
struct dxgallocation *alloc;
250+
struct dxgsyncobject *syncobj;
231251

232252
DXG_TRACE("Destroying device: %p", device);
233253
dxgdevice_acquire_alloc_list_lock(device);
234254
list_for_each_entry(alloc, &device->alloc_list_head, alloc_list_entry) {
235255
dxgallocation_stop(alloc);
236256
}
237257
dxgdevice_release_alloc_list_lock(device);
258+
259+
hmgrtable_lock(&device->process->handle_table, DXGLOCK_EXCL);
260+
list_for_each_entry(syncobj, &device->syncobj_list_head,
261+
syncobj_list_entry) {
262+
dxgsyncobject_stop(syncobj);
263+
}
264+
hmgrtable_unlock(&device->process->handle_table, DXGLOCK_EXCL);
265+
DXG_TRACE("Device stopped: %p", device);
238266
}
239267

240268
void dxgdevice_mark_destroyed(struct dxgdevice *device)
@@ -263,6 +291,20 @@ void dxgdevice_destroy(struct dxgdevice *device)
263291

264292
dxgdevice_acquire_alloc_list_lock(device);
265293

294+
while (!list_empty(&device->syncobj_list_head)) {
295+
struct dxgsyncobject *syncobj =
296+
list_first_entry(&device->syncobj_list_head,
297+
struct dxgsyncobject,
298+
syncobj_list_entry);
299+
list_del(&syncobj->syncobj_list_entry);
300+
syncobj->syncobj_list_entry.next = NULL;
301+
dxgdevice_release_alloc_list_lock(device);
302+
303+
dxgsyncobject_destroy(process, syncobj);
304+
305+
dxgdevice_acquire_alloc_list_lock(device);
306+
}
307+
266308
{
267309
struct dxgallocation *alloc;
268310
struct dxgallocation *tmp;
@@ -565,6 +607,30 @@ void dxgdevice_release(struct kref *refcount)
565607
kfree(device);
566608
}
567609

610+
void dxgdevice_add_syncobj(struct dxgdevice *device,
611+
struct dxgsyncobject *syncobj)
612+
{
613+
dxgdevice_acquire_alloc_list_lock(device);
614+
list_add_tail(&syncobj->syncobj_list_entry, &device->syncobj_list_head);
615+
kref_get(&syncobj->syncobj_kref);
616+
dxgdevice_release_alloc_list_lock(device);
617+
}
618+
619+
void dxgdevice_remove_syncobj(struct dxgsyncobject *entry)
620+
{
621+
struct dxgdevice *device = entry->device;
622+
623+
dxgdevice_acquire_alloc_list_lock(device);
624+
if (entry->syncobj_list_entry.next) {
625+
list_del(&entry->syncobj_list_entry);
626+
entry->syncobj_list_entry.next = NULL;
627+
kref_put(&entry->syncobj_kref, dxgsyncobject_release);
628+
}
629+
dxgdevice_release_alloc_list_lock(device);
630+
kref_put(&device->device_kref, dxgdevice_release);
631+
entry->device = NULL;
632+
}
633+
568634
struct dxgcontext *dxgcontext_create(struct dxgdevice *device)
569635
{
570636
struct dxgcontext *context;
@@ -812,3 +878,121 @@ void dxgprocess_adapter_remove_device(struct dxgdevice *device)
812878
}
813879
mutex_unlock(&device->adapter_info->device_list_mutex);
814880
}
881+
882+
struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
883+
struct dxgdevice *device,
884+
struct dxgadapter *adapter,
885+
enum
886+
d3dddi_synchronizationobject_type
887+
type,
888+
struct
889+
d3dddi_synchronizationobject_flags
890+
flags)
891+
{
892+
struct dxgsyncobject *syncobj;
893+
894+
syncobj = kzalloc(sizeof(*syncobj), GFP_KERNEL);
895+
if (syncobj == NULL)
896+
goto cleanup;
897+
syncobj->type = type;
898+
syncobj->process = process;
899+
switch (type) {
900+
case _D3DDDI_MONITORED_FENCE:
901+
case _D3DDDI_PERIODIC_MONITORED_FENCE:
902+
syncobj->monitored_fence = 1;
903+
break;
904+
default:
905+
break;
906+
}
907+
if (flags.shared) {
908+
syncobj->shared = 1;
909+
if (!flags.nt_security_sharing) {
910+
DXG_ERR("nt_security_sharing must be set");
911+
goto cleanup;
912+
}
913+
}
914+
915+
kref_init(&syncobj->syncobj_kref);
916+
917+
if (syncobj->monitored_fence) {
918+
syncobj->device = device;
919+
syncobj->device_handle = device->handle;
920+
kref_get(&device->device_kref);
921+
dxgdevice_add_syncobj(device, syncobj);
922+
} else {
923+
dxgadapter_add_syncobj(adapter, syncobj);
924+
}
925+
syncobj->adapter = adapter;
926+
kref_get(&adapter->adapter_kref);
927+
928+
DXG_TRACE("Syncobj created: %p", syncobj);
929+
return syncobj;
930+
cleanup:
931+
if (syncobj)
932+
kfree(syncobj);
933+
return NULL;
934+
}
935+
936+
void dxgsyncobject_destroy(struct dxgprocess *process,
937+
struct dxgsyncobject *syncobj)
938+
{
939+
int destroyed;
940+
941+
DXG_TRACE("Destroying syncobj: %p", syncobj);
942+
943+
dxgsyncobject_stop(syncobj);
944+
945+
destroyed = test_and_set_bit(0, &syncobj->flags);
946+
if (!destroyed) {
947+
DXG_TRACE("Deleting handle: %x", syncobj->handle.v);
948+
hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
949+
if (syncobj->handle.v) {
950+
hmgrtable_free_handle(&process->handle_table,
951+
HMGRENTRY_TYPE_DXGSYNCOBJECT,
952+
syncobj->handle);
953+
syncobj->handle.v = 0;
954+
kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
955+
}
956+
hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
957+
958+
if (syncobj->monitored_fence)
959+
dxgdevice_remove_syncobj(syncobj);
960+
else
961+
dxgadapter_remove_syncobj(syncobj);
962+
if (syncobj->adapter) {
963+
kref_put(&syncobj->adapter->adapter_kref,
964+
dxgadapter_release);
965+
syncobj->adapter = NULL;
966+
}
967+
}
968+
kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
969+
}
970+
971+
void dxgsyncobject_stop(struct dxgsyncobject *syncobj)
972+
{
973+
int stopped = test_and_set_bit(1, &syncobj->flags);
974+
975+
if (!stopped) {
976+
DXG_TRACE("Stopping syncobj");
977+
if (syncobj->monitored_fence) {
978+
if (syncobj->mapped_address) {
979+
int ret =
980+
dxg_unmap_iospace(syncobj->mapped_address,
981+
PAGE_SIZE);
982+
983+
(void)ret;
984+
DXG_TRACE("unmap fence %d %p",
985+
ret, syncobj->mapped_address);
986+
syncobj->mapped_address = NULL;
987+
}
988+
}
989+
}
990+
}
991+
992+
void dxgsyncobject_release(struct kref *refcount)
993+
{
994+
struct dxgsyncobject *syncobj;
995+
996+
syncobj = container_of(refcount, struct dxgsyncobject, syncobj_kref);
997+
kfree(syncobj);
998+
}

drivers/hv/dxgkrnl/dxgkrnl.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct dxgdevice;
3838
struct dxgcontext;
3939
struct dxgallocation;
4040
struct dxgresource;
41+
struct dxgsyncobject;
4142

4243
/*
4344
* Driver private data.
@@ -100,6 +101,56 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hdev);
100101
void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch);
101102
void dxgvmbuschannel_receive(void *ctx);
102103

104+
/*
105+
* This is GPU synchronization object, which is used to synchronize execution
106+
* between GPU contextx/hardware queues or for tracking GPU execution progress.
107+
* A dxgsyncobject is created when somebody creates a syncobject or opens a
108+
* shared syncobject.
109+
* A syncobject belongs to an adapter, unless it is a cross-adapter object.
110+
* Cross adapter syncobjects are currently not implemented.
111+
*
112+
* D3DDDI_MONITORED_FENCE and D3DDDI_PERIODIC_MONITORED_FENCE are called
113+
* "device" syncobject, because the belong to a device (dxgdevice).
114+
* Device syncobjects are inserted to a list in dxgdevice.
115+
*
116+
*/
117+
struct dxgsyncobject {
118+
struct kref syncobj_kref;
119+
enum d3dddi_synchronizationobject_type type;
120+
/*
121+
* List entry in dxgdevice for device sync objects.
122+
* List entry in dxgadapter for other objects
123+
*/
124+
struct list_head syncobj_list_entry;
125+
/* Adapter, the syncobject belongs to. NULL for stopped sync obejcts. */
126+
struct dxgadapter *adapter;
127+
/*
128+
* Pointer to the device, which was used to create the object.
129+
* This is NULL for non-device syncbjects
130+
*/
131+
struct dxgdevice *device;
132+
struct dxgprocess *process;
133+
/* CPU virtual address of the fence value for "device" syncobjects */
134+
void *mapped_address;
135+
/* Handle in the process handle table */
136+
struct d3dkmthandle handle;
137+
/* Cached handle of the device. Used to avoid device dereference. */
138+
struct d3dkmthandle device_handle;
139+
union {
140+
struct {
141+
/* Must be the first bit */
142+
u32 destroyed:1;
143+
/* Must be the second bit */
144+
u32 stopped:1;
145+
/* device syncobject */
146+
u32 monitored_fence:1;
147+
u32 shared:1;
148+
u32 reserved:27;
149+
};
150+
long flags;
151+
};
152+
};
153+
103154
/*
104155
* The structure defines an offered vGPU vm bus channel.
105156
*/
@@ -109,6 +160,20 @@ struct dxgvgpuchannel {
109160
struct hv_device *hdev;
110161
};
111162

163+
struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
164+
struct dxgdevice *device,
165+
struct dxgadapter *adapter,
166+
enum
167+
d3dddi_synchronizationobject_type
168+
type,
169+
struct
170+
d3dddi_synchronizationobject_flags
171+
flags);
172+
void dxgsyncobject_destroy(struct dxgprocess *process,
173+
struct dxgsyncobject *syncobj);
174+
void dxgsyncobject_stop(struct dxgsyncobject *syncobj);
175+
void dxgsyncobject_release(struct kref *refcount);
176+
112177
struct dxgglobal {
113178
struct dxgdriver *drvdata;
114179
struct dxgvmbuschannel channel;
@@ -271,6 +336,8 @@ struct dxgadapter {
271336
struct list_head adapter_list_entry;
272337
/* The list of dxgprocess_adapter entries */
273338
struct list_head adapter_process_list_head;
339+
/* List of all non-device dxgsyncobject objects */
340+
struct list_head syncobj_list_head;
274341
/* This lock protects shared resource and syncobject lists */
275342
struct rw_semaphore shared_resource_list_lock;
276343
struct pci_dev *pci_dev;
@@ -296,6 +363,9 @@ void dxgadapter_release_lock_shared(struct dxgadapter *adapter);
296363
int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter);
297364
void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter);
298365
void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter);
366+
void dxgadapter_add_syncobj(struct dxgadapter *adapter,
367+
struct dxgsyncobject *so);
368+
void dxgadapter_remove_syncobj(struct dxgsyncobject *so);
299369
void dxgadapter_add_process(struct dxgadapter *adapter,
300370
struct dxgprocess_adapter *process_info);
301371
void dxgadapter_remove_process(struct dxgprocess_adapter *process_info);
@@ -325,6 +395,7 @@ struct dxgdevice {
325395
struct list_head resource_list_head;
326396
/* List of paging queues. Protected by process handle table lock. */
327397
struct list_head pqueue_list_head;
398+
struct list_head syncobj_list_head;
328399
struct d3dkmthandle handle;
329400
enum d3dkmt_deviceexecution_state execution_state;
330401
u32 handle_valid;
@@ -345,6 +416,8 @@ void dxgdevice_remove_alloc_safe(struct dxgdevice *dev,
345416
struct dxgallocation *a);
346417
void dxgdevice_add_resource(struct dxgdevice *dev, struct dxgresource *res);
347418
void dxgdevice_remove_resource(struct dxgdevice *dev, struct dxgresource *res);
419+
void dxgdevice_add_syncobj(struct dxgdevice *dev, struct dxgsyncobject *so);
420+
void dxgdevice_remove_syncobj(struct dxgsyncobject *so);
348421
bool dxgdevice_is_active(struct dxgdevice *dev);
349422
void dxgdevice_acquire_context_list_lock(struct dxgdevice *dev);
350423
void dxgdevice_release_context_list_lock(struct dxgdevice *dev);
@@ -455,6 +528,7 @@ void dxgallocation_free_handle(struct dxgallocation *a);
455528
long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2);
456529
long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2);
457530

531+
int dxg_unmap_iospace(void *va, u32 size);
458532
/*
459533
* The convention is that VNBus instance id is a GUID, but the host sets
460534
* the lower part of the value to the host adapter LUID. The function
@@ -514,6 +588,12 @@ int dxgvmb_send_create_allocation(struct dxgprocess *pr, struct dxgdevice *dev,
514588
int dxgvmb_send_destroy_allocation(struct dxgprocess *pr, struct dxgdevice *dev,
515589
struct d3dkmt_destroyallocation2 *args,
516590
struct d3dkmthandle *alloc_handles);
591+
int dxgvmb_send_create_sync_object(struct dxgprocess *pr,
592+
struct dxgadapter *adapter,
593+
struct d3dkmt_createsynchronizationobject2
594+
*args, struct dxgsyncobject *so);
595+
int dxgvmb_send_destroy_sync_object(struct dxgprocess *pr,
596+
struct d3dkmthandle h);
517597
int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
518598
struct dxgadapter *adapter,
519599
struct d3dkmt_queryadapterinfo *args);

drivers/hv/dxgkrnl/dxgmodule.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
162162
init_rwsem(&adapter->core_lock);
163163

164164
INIT_LIST_HEAD(&adapter->adapter_process_list_head);
165+
INIT_LIST_HEAD(&adapter->syncobj_list_head);
165166
init_rwsem(&adapter->shared_resource_list_lock);
166167
adapter->pci_dev = dev;
167168
guid_to_luid(guid, &adapter->luid);

0 commit comments

Comments
 (0)