From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Iouri Tarassov Date: Tue, 1 Feb 2022 13:59:23 -0800 Subject: drivers: hv: dxgkrnl: Operations using sync objects Implement ioctls to submit operations with compute device sync objects: - the LX_DXSIGNALSYNCHRONIZATIONOBJECT ioctl. The ioctl is used to submit a signal to a sync object. - the LX_DXWAITFORSYNCHRONIZATIONOBJECT ioctl. The ioctl is used to submit a wait for a sync object - the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU ioctl The ioctl is used to signal to a monitored fence sync object from a CPU thread. - the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU ioctl. The ioctl is used to submit a signal to a monitored fence sync object.. - the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2 ioctl. The ioctl is used to submit a signal to a monitored fence sync object. - the LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU ioctl. The ioctl is used to submit a wait for a monitored fence sync object. Compute device synchronization objects are used to synchronize execution of DMA buffers between different execution contexts. Operations with sync objects include "signal" and "wait". A wait for a sync object is satisfied when the sync object is signaled. A signal operation could be submitted to a compute device context or the sync object could be signaled by a CPU thread. To improve performance, submitting operations to the host is done asynchronously when the host supports it. Signed-off-by: Iouri Tarassov [kms: Forward port to v6.1] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 38 +- drivers/hv/dxgkrnl/dxgkrnl.h | 62 + drivers/hv/dxgkrnl/dxgmodule.c | 102 +- drivers/hv/dxgkrnl/dxgvmbus.c | 219 ++- drivers/hv/dxgkrnl/dxgvmbus.h | 48 + drivers/hv/dxgkrnl/ioctl.c | 702 +++++++++- drivers/hv/dxgkrnl/misc.h | 2 + include/uapi/misc/d3dkmthk.h | 159 +++ 8 files changed, 1311 insertions(+), 21 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c index 111111111111..222222222222 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -249,7 +249,7 @@ void dxgdevice_stop(struct dxgdevice *device) struct dxgallocation *alloc; struct dxgsyncobject *syncobj; - DXG_TRACE("Destroying device: %p", device); + DXG_TRACE("Stopping device: %p", device); dxgdevice_acquire_alloc_list_lock(device); list_for_each_entry(alloc, &device->alloc_list_head, alloc_list_entry) { dxgallocation_stop(alloc); @@ -743,15 +743,13 @@ void dxgallocation_destroy(struct dxgallocation *alloc) } #ifdef _MAIN_KERNEL_ if (alloc->gpadl.gpadl_handle) { - DXG_TRACE("Teardown gpadl %d", - alloc->gpadl.gpadl_handle); + DXG_TRACE("Teardown gpadl %d", alloc->gpadl.gpadl_handle); vmbus_teardown_gpadl(dxgglobal_get_vmbus(), &alloc->gpadl); alloc->gpadl.gpadl_handle = 0; } else if (alloc->gpadl) { - DXG_TRACE("Teardown gpadl %d", - alloc->gpadl); + DXG_TRACE("Teardown gpadl %d", alloc->gpadl); vmbus_teardown_gpadl(dxgglobal_get_vmbus(), alloc->gpadl); alloc->gpadl = 0; } @@ -901,6 +899,13 @@ struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process, case _D3DDDI_PERIODIC_MONITORED_FENCE: syncobj->monitored_fence = 1; break; + case _D3DDDI_CPU_NOTIFICATION: + syncobj->cpu_event = 1; + syncobj->host_event = kzalloc(sizeof(*syncobj->host_event), + GFP_KERNEL); + if (syncobj->host_event == NULL) + goto cleanup; + break; default: break; } @@ -928,6 +933,8 @@ struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process, DXG_TRACE("Syncobj created: %p", syncobj); return syncobj; cleanup: + if (syncobj->host_event) + kfree(syncobj->host_event); if (syncobj) kfree(syncobj); return NULL; @@ -937,6 +944,7 @@ void dxgsyncobject_destroy(struct dxgprocess *process, struct dxgsyncobject *syncobj) { int destroyed; + struct dxghosteventcpu *host_event; DXG_TRACE("Destroying syncobj: %p", syncobj); @@ -955,6 +963,16 @@ void dxgsyncobject_destroy(struct dxgprocess *process, } hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + if (syncobj->cpu_event) { + host_event = syncobj->host_event; + if (host_event->cpu_event) { + eventfd_ctx_put(host_event->cpu_event); + if (host_event->hdr.event_id) + dxgglobal_remove_host_event( + &host_event->hdr); + host_event->cpu_event = NULL; + } + } if (syncobj->monitored_fence) dxgdevice_remove_syncobj(syncobj); else @@ -971,16 +989,14 @@ void dxgsyncobject_destroy(struct dxgprocess *process, void dxgsyncobject_stop(struct dxgsyncobject *syncobj) { int stopped = test_and_set_bit(1, &syncobj->flags); + int ret; if (!stopped) { DXG_TRACE("Stopping syncobj"); if (syncobj->monitored_fence) { if (syncobj->mapped_address) { - int ret = - dxg_unmap_iospace(syncobj->mapped_address, - PAGE_SIZE); - - (void)ret; + ret = dxg_unmap_iospace(syncobj->mapped_address, + PAGE_SIZE); DXG_TRACE("unmap fence %d %p", ret, syncobj->mapped_address); syncobj->mapped_address = NULL; @@ -994,5 +1010,7 @@ void dxgsyncobject_release(struct kref *refcount) struct dxgsyncobject *syncobj; syncobj = container_of(refcount, struct dxgsyncobject, syncobj_kref); + if (syncobj->host_event) + kfree(syncobj->host_event); kfree(syncobj); } diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 111111111111..222222222222 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -101,6 +101,29 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hdev); void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch); void dxgvmbuschannel_receive(void *ctx); +/* + * The structure describes an event, which will be signaled by + * a message from host. + */ +enum dxghosteventtype { + dxghostevent_cpu_event = 1, +}; + +struct dxghostevent { + struct list_head host_event_list_entry; + u64 event_id; + enum dxghosteventtype event_type; +}; + +struct dxghosteventcpu { + struct dxghostevent hdr; + struct dxgprocess *process; + struct eventfd_ctx *cpu_event; + struct completion *completion_event; + bool destroy_after_signal; + bool remove_from_list; +}; + /* * This is GPU synchronization object, which is used to synchronize execution * between GPU contextx/hardware queues or for tracking GPU execution progress. @@ -130,6 +153,8 @@ struct dxgsyncobject { */ struct dxgdevice *device; struct dxgprocess *process; + /* Used by D3DDDI_CPU_NOTIFICATION objects */ + struct dxghosteventcpu *host_event; /* CPU virtual address of the fence value for "device" syncobjects */ void *mapped_address; /* Handle in the process handle table */ @@ -144,6 +169,7 @@ struct dxgsyncobject { u32 stopped:1; /* device syncobject */ u32 monitored_fence:1; + u32 cpu_event:1; u32 shared:1; u32 reserved:27; }; @@ -206,6 +232,11 @@ struct dxgglobal { /* protects the dxgprocess_adapter lists */ struct mutex process_adapter_mutex; + /* list of events, waiting to be signaled by the host */ + struct list_head host_event_list_head; + spinlock_t host_event_list_mutex; + atomic64_t host_event_id; + bool global_channel_initialized; bool async_msg_enabled; bool misc_registered; @@ -228,6 +259,11 @@ struct vmbus_channel *dxgglobal_get_vmbus(void); struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel(void); void dxgglobal_acquire_process_adapter_lock(void); void dxgglobal_release_process_adapter_lock(void); +void dxgglobal_add_host_event(struct dxghostevent *hostevent); +void dxgglobal_remove_host_event(struct dxghostevent *hostevent); +u64 dxgglobal_new_host_event_id(void); +void dxgglobal_signal_host_event(u64 event_id); +struct dxghostevent *dxgglobal_get_host_event(u64 event_id); int dxgglobal_acquire_channel_lock(void); void dxgglobal_release_channel_lock(void); @@ -594,6 +630,31 @@ int dxgvmb_send_create_sync_object(struct dxgprocess *pr, *args, struct dxgsyncobject *so); int dxgvmb_send_destroy_sync_object(struct dxgprocess *pr, struct d3dkmthandle h); +int dxgvmb_send_signal_sync_object(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dddicb_signalflags flags, + u64 legacy_fence_value, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle *object, + u32 context_count, + struct d3dkmthandle *contexts, + u32 fence_count, u64 *fences, + struct eventfd_ctx *cpu_event, + struct d3dkmthandle device); +int dxgvmb_send_wait_sync_object_gpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle *objects, + u64 *fences, + bool legacy_fence); +int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct + d3dkmt_waitforsynchronizationobjectfromcpu + *args, + u64 cpu_event); int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); @@ -609,6 +670,7 @@ int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel, void *command, u32 cmd_size); +void signal_host_cpu_event(struct dxghostevent *eventhdr); int ntstatus2int(struct ntstatus status); #ifdef DEBUG diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 111111111111..222222222222 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -123,6 +123,102 @@ static struct dxgadapter *find_adapter(struct winluid *luid) return adapter; } +void dxgglobal_add_host_event(struct dxghostevent *event) +{ + struct dxgglobal *dxgglobal = dxggbl(); + + spin_lock_irq(&dxgglobal->host_event_list_mutex); + list_add_tail(&event->host_event_list_entry, + &dxgglobal->host_event_list_head); + spin_unlock_irq(&dxgglobal->host_event_list_mutex); +} + +void dxgglobal_remove_host_event(struct dxghostevent *event) +{ + struct dxgglobal *dxgglobal = dxggbl(); + + spin_lock_irq(&dxgglobal->host_event_list_mutex); + if (event->host_event_list_entry.next != NULL) { + list_del(&event->host_event_list_entry); + event->host_event_list_entry.next = NULL; + } + spin_unlock_irq(&dxgglobal->host_event_list_mutex); +} + +void signal_host_cpu_event(struct dxghostevent *eventhdr) +{ + struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr; + + if (event->remove_from_list || + event->destroy_after_signal) { + list_del(&eventhdr->host_event_list_entry); + eventhdr->host_event_list_entry.next = NULL; + } + if (event->cpu_event) { + DXG_TRACE("signal cpu event"); + eventfd_signal(event->cpu_event, 1); + if (event->destroy_after_signal) + eventfd_ctx_put(event->cpu_event); + } else { + DXG_TRACE("signal completion"); + complete(event->completion_event); + } + if (event->destroy_after_signal) { + DXG_TRACE("destroying event %p", event); + kfree(event); + } +} + +void dxgglobal_signal_host_event(u64 event_id) +{ + struct dxghostevent *event; + unsigned long flags; + struct dxgglobal *dxgglobal = dxggbl(); + + DXG_TRACE("Signaling host event %lld", event_id); + + spin_lock_irqsave(&dxgglobal->host_event_list_mutex, flags); + list_for_each_entry(event, &dxgglobal->host_event_list_head, + host_event_list_entry) { + if (event->event_id == event_id) { + DXG_TRACE("found event to signal"); + if (event->event_type == dxghostevent_cpu_event) + signal_host_cpu_event(event); + else + DXG_ERR("Unknown host event type"); + break; + } + } + spin_unlock_irqrestore(&dxgglobal->host_event_list_mutex, flags); +} + +struct dxghostevent *dxgglobal_get_host_event(u64 event_id) +{ + struct dxghostevent *entry; + struct dxghostevent *event = NULL; + struct dxgglobal *dxgglobal = dxggbl(); + + spin_lock_irq(&dxgglobal->host_event_list_mutex); + list_for_each_entry(entry, &dxgglobal->host_event_list_head, + host_event_list_entry) { + if (entry->event_id == event_id) { + list_del(&entry->host_event_list_entry); + entry->host_event_list_entry.next = NULL; + event = entry; + break; + } + } + spin_unlock_irq(&dxgglobal->host_event_list_mutex); + return event; +} + +u64 dxgglobal_new_host_event_id(void) +{ + struct dxgglobal *dxgglobal = dxggbl(); + + return atomic64_inc_return(&dxgglobal->host_event_id); +} + void dxgglobal_acquire_process_adapter_lock(void) { struct dxgglobal *dxgglobal = dxggbl(); @@ -720,12 +816,16 @@ static struct dxgglobal *dxgglobal_create(void) INIT_LIST_HEAD(&dxgglobal->vgpu_ch_list_head); INIT_LIST_HEAD(&dxgglobal->adapter_list_head); init_rwsem(&dxgglobal->adapter_list_lock); - init_rwsem(&dxgglobal->channel_lock); + INIT_LIST_HEAD(&dxgglobal->host_event_list_head); + spin_lock_init(&dxgglobal->host_event_list_mutex); + atomic64_set(&dxgglobal->host_event_id, 1); + #ifdef DEBUG dxgk_validate_ioctls(); #endif + return dxgglobal; } diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 111111111111..222222222222 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -281,6 +281,22 @@ static void command_vm_to_host_init1(struct dxgkvmb_command_vm_to_host *command, command->channel_type = DXGKVMB_VM_TO_HOST; } +static void signal_guest_event(struct dxgkvmb_command_host_to_vm *packet, + u32 packet_length) +{ + struct dxgkvmb_command_signalguestevent *command = (void *)packet; + + if (packet_length < sizeof(struct dxgkvmb_command_signalguestevent)) { + DXG_ERR("invalid signal guest event packet size"); + return; + } + if (command->event == 0) { + DXG_ERR("invalid event pointer"); + return; + } + dxgglobal_signal_host_event(command->event); +} + static void process_inband_packet(struct dxgvmbuschannel *channel, struct vmpacket_descriptor *desc) { @@ -297,6 +313,7 @@ static void process_inband_packet(struct dxgvmbuschannel *channel, switch (packet->command_type) { case DXGK_VMBCOMMAND_SIGNALGUESTEVENT: case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE: + signal_guest_event(packet, packet_length); break; case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION: break; @@ -959,7 +976,7 @@ dxgvmb_send_create_context(struct dxgadapter *adapter, command->priv_drv_data, args->priv_drv_data_size); if (ret) { - dev_err(DXGDEV, + DXG_ERR( "Faled to copy private data to user"); ret = -EINVAL; dxgvmb_send_destroy_context(adapter, process, @@ -1706,6 +1723,206 @@ dxgvmb_send_create_sync_object(struct dxgprocess *process, return ret; } +int dxgvmb_send_signal_sync_object(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dddicb_signalflags flags, + u64 legacy_fence_value, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle __user *objects, + u32 context_count, + struct d3dkmthandle __user *contexts, + u32 fence_count, + u64 __user *fences, + struct eventfd_ctx *cpu_event_handle, + struct d3dkmthandle device) +{ + int ret; + struct dxgkvmb_command_signalsyncobject *command; + u32 object_size = object_count * sizeof(struct d3dkmthandle); + u32 context_size = context_count * sizeof(struct d3dkmthandle); + u32 fence_size = fences ? fence_count * sizeof(u64) : 0; + u8 *current_pos; + u32 cmd_size = sizeof(struct dxgkvmb_command_signalsyncobject) + + object_size + context_size + fence_size; + struct dxgvmbusmsg msg = {.hdr = NULL}; + struct dxgglobal *dxgglobal = dxggbl(); + + if (context.v) + cmd_size += sizeof(struct d3dkmthandle); + + ret = init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command = (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_SIGNALSYNCOBJECT, + process->host_handle); + + if (flags.enqueue_cpu_event) + command->cpu_event_handle = (u64) cpu_event_handle; + else + command->device = device; + command->flags = flags; + command->fence_value = legacy_fence_value; + command->object_count = object_count; + command->context_count = context_count; + current_pos = (u8 *) &command[1]; + ret = copy_from_user(current_pos, objects, object_size); + if (ret) { + DXG_ERR("Failed to read objects %p %d", + objects, object_size); + ret = -EINVAL; + goto cleanup; + } + current_pos += object_size; + if (context.v) { + command->context_count++; + *(struct d3dkmthandle *) current_pos = context; + current_pos += sizeof(struct d3dkmthandle); + } + if (context_size) { + ret = copy_from_user(current_pos, contexts, context_size); + if (ret) { + DXG_ERR("Failed to read contexts %p %d", + contexts, context_size); + ret = -EINVAL; + goto cleanup; + } + current_pos += context_size; + } + if (fence_size) { + ret = copy_from_user(current_pos, fences, fence_size); + if (ret) { + DXG_ERR("Failed to read fences %p %d", + fences, fence_size); + ret = -EINVAL; + goto cleanup; + } + } + + if (dxgglobal->async_msg_enabled) { + command->hdr.async_msg = 1; + ret = dxgvmb_send_async_msg(msg.channel, msg.hdr, msg.size); + } else { + ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, + msg.size); + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct + d3dkmt_waitforsynchronizationobjectfromcpu + *args, + u64 cpu_event) +{ + int ret = -EINVAL; + struct dxgkvmb_command_waitforsyncobjectfromcpu *command; + u32 object_size = args->object_count * sizeof(struct d3dkmthandle); + u32 fence_size = args->object_count * sizeof(u64); + u8 *current_pos; + u32 cmd_size = sizeof(*command) + object_size + fence_size; + struct dxgvmbusmsg msg = {.hdr = NULL}; + + ret = init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command = (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMCPU, + process->host_handle); + command->device = args->device; + command->flags = args->flags; + command->object_count = args->object_count; + command->guest_event_pointer = (u64) cpu_event; + current_pos = (u8 *) &command[1]; + + ret = copy_from_user(current_pos, args->objects, object_size); + if (ret) { + DXG_ERR("failed to copy objects"); + ret = -EINVAL; + goto cleanup; + } + current_pos += object_size; + ret = copy_from_user(current_pos, args->fence_values, + fence_size); + if (ret) { + DXG_ERR("failed to copy fences"); + ret = -EINVAL; + goto cleanup; + } + + ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_wait_sync_object_gpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle *objects, + u64 *fences, + bool legacy_fence) +{ + int ret; + struct dxgkvmb_command_waitforsyncobjectfromgpu *command; + u32 fence_size = object_count * sizeof(u64); + u32 object_size = object_count * sizeof(struct d3dkmthandle); + u8 *current_pos; + u32 cmd_size = object_size + fence_size - sizeof(u64) + + sizeof(struct dxgkvmb_command_waitforsyncobjectfromgpu); + struct dxgvmbusmsg msg = {.hdr = NULL}; + struct dxgglobal *dxgglobal = dxggbl(); + + if (object_count == 0 || object_count > D3DDDI_MAX_OBJECT_WAITED_ON) { + ret = -EINVAL; + goto cleanup; + } + ret = init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command = (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMGPU, + process->host_handle); + command->context = context; + command->object_count = object_count; + command->legacy_fence_object = legacy_fence; + current_pos = (u8 *) command->fence_values; + memcpy(current_pos, fences, fence_size); + current_pos += fence_size; + memcpy(current_pos, objects, object_size); + + if (dxgglobal->async_msg_enabled) { + command->hdr.async_msg = 1; + ret = dxgvmb_send_async_msg(msg.channel, msg.hdr, msg.size); + } else { + ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, + msg.size); + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 111111111111..222222222222 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -165,6 +165,13 @@ struct dxgkvmb_command_host_to_vm { enum dxgkvmb_commandtype_host_to_vm command_type; }; +struct dxgkvmb_command_signalguestevent { + struct dxgkvmb_command_host_to_vm hdr; + u64 event; + u64 process_id; + bool dereference_event; +}; + /* Returns ntstatus */ struct dxgkvmb_command_setiospaceregion { struct dxgkvmb_command_vm_to_host hdr; @@ -430,4 +437,45 @@ struct dxgkvmb_command_destroysyncobject { struct d3dkmthandle sync_object; }; +/* The command returns ntstatus */ +struct dxgkvmb_command_signalsyncobject { + struct dxgkvmb_command_vgpu_to_host hdr; + u32 object_count; + struct d3dddicb_signalflags flags; + u32 context_count; + u64 fence_value; + union { + /* Pointer to the guest event object */ + u64 cpu_event_handle; + /* Non zero when signal from CPU is done */ + struct d3dkmthandle device; + }; + /* struct d3dkmthandle ObjectHandleArray[object_count] */ + /* struct d3dkmthandle ContextArray[context_count] */ + /* u64 MonitoredFenceValueArray[object_count] */ +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_waitforsyncobjectfromcpu { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + u32 object_count; + struct d3dddi_waitforsynchronizationobjectfromcpu_flags flags; + u64 guest_event_pointer; + bool dereference_event; + /* struct d3dkmthandle ObjectHandleArray[object_count] */ + /* u64 FenceValueArray [object_count] */ +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_waitforsyncobjectfromgpu { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle context; + /* Must be 1 when bLegacyFenceObject is TRUE */ + u32 object_count; + bool legacy_fence_object; + u64 fence_values[1]; + /* struct d3dkmthandle ObjectHandles[object_count] */ +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 111111111111..222222222222 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -759,7 +759,7 @@ get_standard_alloc_priv_data(struct dxgdevice *device, res_priv_data = vzalloc(res_priv_data_size); if (res_priv_data == NULL) { ret = -ENOMEM; - dev_err(DXGDEV, + DXG_ERR( "failed to alloc memory for res priv data: %d", res_priv_data_size); goto cleanup; @@ -1065,7 +1065,7 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs) alloc_info[i].priv_drv_data, priv_data_size); if (ret) { - dev_err(DXGDEV, + DXG_ERR( "failed to copy priv data"); ret = -EFAULT; goto cleanup; @@ -1348,8 +1348,10 @@ dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs) struct d3dkmt_createsynchronizationobject2 args; struct dxgdevice *device = NULL; struct dxgadapter *adapter = NULL; + struct eventfd_ctx *event = NULL; struct dxgsyncobject *syncobj = NULL; bool device_lock_acquired = false; + struct dxghosteventcpu *host_event = NULL; ret = copy_from_user(&args, inargs, sizeof(args)); if (ret) { @@ -1384,6 +1386,27 @@ dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs) goto cleanup; } + if (args.info.type == _D3DDDI_CPU_NOTIFICATION) { + event = eventfd_ctx_fdget((int) + args.info.cpu_notification.event); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event = NULL; + ret = -EINVAL; + goto cleanup; + } + host_event = syncobj->host_event; + host_event->hdr.event_id = dxgglobal_new_host_event_id(); + host_event->cpu_event = event; + host_event->remove_from_list = false; + host_event->destroy_after_signal = false; + host_event->hdr.event_type = dxghostevent_cpu_event; + dxgglobal_add_host_event(&host_event->hdr); + args.info.cpu_notification.event = host_event->hdr.event_id; + DXG_TRACE("creating CPU notification event: %lld", + args.info.cpu_notification.event); + } + ret = dxgvmb_send_create_sync_object(process, adapter, &args, syncobj); if (ret < 0) goto cleanup; @@ -1411,7 +1434,10 @@ dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs) if (args.sync_object.v) dxgvmb_send_destroy_sync_object(process, args.sync_object); + event = NULL; } + if (event) + eventfd_ctx_put(event); } if (adapter) dxgadapter_release_lock_shared(adapter); @@ -1467,6 +1493,659 @@ dxgkio_destroy_sync_object(struct dxgprocess *process, void *__user inargs) return ret; } +static int +dxgkio_signal_sync_object(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_signalsynchronizationobject2 args; + struct d3dkmt_signalsynchronizationobject2 *__user in_args = inargs; + struct dxgdevice *device = NULL; + struct dxgadapter *adapter = NULL; + int ret; + u32 fence_count = 1; + struct eventfd_ctx *event = NULL; + struct dxghosteventcpu *host_event = NULL; + bool host_event_added = false; + u64 host_event_id = 0; + + ret = copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret = -EINVAL; + goto cleanup; + } + + if (args.context_count >= D3DDDI_MAX_BROADCAST_CONTEXT || + args.object_count > D3DDDI_MAX_OBJECT_SIGNALED) { + ret = -EINVAL; + goto cleanup; + } + + if (args.flags.enqueue_cpu_event) { + host_event = kzalloc(sizeof(*host_event), GFP_KERNEL); + if (host_event == NULL) { + ret = -ENOMEM; + goto cleanup; + } + host_event->process = process; + event = eventfd_ctx_fdget((int)args.cpu_event_handle); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event = NULL; + ret = -EINVAL; + goto cleanup; + } + fence_count = 0; + host_event->cpu_event = event; + host_event_id = dxgglobal_new_host_event_id(); + host_event->hdr.event_type = dxghostevent_cpu_event; + host_event->hdr.event_id = host_event_id; + host_event->remove_from_list = true; + host_event->destroy_after_signal = true; + dxgglobal_add_host_event(&host_event->hdr); + host_event_added = true; + } + + device = dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device == NULL) { + ret = -EINVAL; + goto cleanup; + } + + adapter = device->adapter; + ret = dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter = NULL; + goto cleanup; + } + + ret = dxgvmb_send_signal_sync_object(process, adapter, + args.flags, args.fence.fence_value, + args.context, args.object_count, + in_args->object_array, + args.context_count, + in_args->contexts, fence_count, + NULL, (void *)host_event_id, + zerohandle); + + /* + * When the send operation succeeds, the host event will be destroyed + * after signal from the host + */ + +cleanup: + + if (ret < 0) { + if (host_event_added) { + /* The event might be signaled and destroyed by host */ + host_event = (struct dxghosteventcpu *) + dxgglobal_get_host_event(host_event_id); + if (host_event) { + eventfd_ctx_put(event); + event = NULL; + kfree(host_event); + host_event = NULL; + } + } + if (event) + eventfd_ctx_put(event); + if (host_event) + kfree(host_event); + } + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_signal_sync_object_cpu(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_signalsynchronizationobjectfromcpu args; + struct dxgdevice *device = NULL; + struct dxgadapter *adapter = NULL; + int ret; + + ret = copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret = -EINVAL; + goto cleanup; + } + if (args.object_count == 0 || + args.object_count > D3DDDI_MAX_OBJECT_SIGNALED) { + DXG_TRACE("Too many syncobjects : %d", args.object_count); + ret = -EINVAL; + goto cleanup; + } + + device = dxgprocess_device_by_handle(process, args.device); + if (device == NULL) { + ret = -EINVAL; + goto cleanup; + } + + adapter = device->adapter; + ret = dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter = NULL; + goto cleanup; + } + + ret = dxgvmb_send_signal_sync_object(process, adapter, + args.flags, 0, zerohandle, + args.object_count, args.objects, 0, + NULL, args.object_count, + args.fence_values, NULL, + args.device); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_signal_sync_object_gpu(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_signalsynchronizationobjectfromgpu args; + struct d3dkmt_signalsynchronizationobjectfromgpu *__user user_args = + inargs; + struct dxgdevice *device = NULL; + struct dxgadapter *adapter = NULL; + struct d3dddicb_signalflags flags = { }; + int ret; + + ret = copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret = -EINVAL; + goto cleanup; + } + + if (args.object_count == 0 || + args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret = -EINVAL; + goto cleanup; + } + + device = dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device == NULL) { + ret = -EINVAL; + goto cleanup; + } + + adapter = device->adapter; + ret = dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter = NULL; + goto cleanup; + } + + ret = dxgvmb_send_signal_sync_object(process, adapter, + flags, 0, zerohandle, + args.object_count, + args.objects, 1, + &user_args->context, + args.object_count, + args.monitored_fence_values, NULL, + zerohandle); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_signal_sync_object_gpu2(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_signalsynchronizationobjectfromgpu2 args; + struct dxgdevice *device = NULL; + struct dxgadapter *adapter = NULL; + struct d3dkmthandle context_handle; + struct eventfd_ctx *event = NULL; + u64 *fences = NULL; + u32 fence_count = 0; + int ret; + struct dxghosteventcpu *host_event = NULL; + bool host_event_added = false; + u64 host_event_id = 0; + + ret = copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret = -EINVAL; + goto cleanup; + } + + if (args.flags.enqueue_cpu_event) { + if (args.object_count != 0 || args.cpu_event_handle == 0) { + DXG_ERR("Bad input in EnqueueCpuEvent: %d %lld", + args.object_count, args.cpu_event_handle); + ret = -EINVAL; + goto cleanup; + } + } else if (args.object_count == 0 || + args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE || + args.context_count == 0 || + args.context_count > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("Invalid input: %d %d", + args.object_count, args.context_count); + ret = -EINVAL; + goto cleanup; + } + + ret = copy_from_user(&context_handle, args.contexts, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy context handle"); + ret = -EINVAL; + goto cleanup; + } + + if (args.flags.enqueue_cpu_event) { + host_event = kzalloc(sizeof(*host_event), GFP_KERNEL); + if (host_event == NULL) { + ret = -ENOMEM; + goto cleanup; + } + host_event->process = process; + event = eventfd_ctx_fdget((int)args.cpu_event_handle); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event = NULL; + ret = -EINVAL; + goto cleanup; + } + fence_count = 0; + host_event->cpu_event = event; + host_event_id = dxgglobal_new_host_event_id(); + host_event->hdr.event_id = host_event_id; + host_event->hdr.event_type = dxghostevent_cpu_event; + host_event->remove_from_list = true; + host_event->destroy_after_signal = true; + dxgglobal_add_host_event(&host_event->hdr); + host_event_added = true; + } else { + fences = args.monitored_fence_values; + fence_count = args.object_count; + } + + device = dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + context_handle); + if (device == NULL) { + ret = -EINVAL; + goto cleanup; + } + + adapter = device->adapter; + ret = dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter = NULL; + goto cleanup; + } + + ret = dxgvmb_send_signal_sync_object(process, adapter, + args.flags, 0, zerohandle, + args.object_count, args.objects, + args.context_count, args.contexts, + fence_count, fences, + (void *)host_event_id, zerohandle); + +cleanup: + + if (ret < 0) { + if (host_event_added) { + /* The event might be signaled and destroyed by host */ + host_event = (struct dxghosteventcpu *) + dxgglobal_get_host_event(host_event_id); + if (host_event) { + eventfd_ctx_put(event); + event = NULL; + kfree(host_event); + host_event = NULL; + } + } + if (event) + eventfd_ctx_put(event); + if (host_event) + kfree(host_event); + } + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_wait_sync_object(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_waitforsynchronizationobject2 args; + struct dxgdevice *device = NULL; + struct dxgadapter *adapter = NULL; + int ret; + + ret = copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret = -EINVAL; + goto cleanup; + } + + if (args.object_count > D3DDDI_MAX_OBJECT_WAITED_ON || + args.object_count == 0) { + ret = -EINVAL; + goto cleanup; + } + + device = dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device == NULL) { + ret = -EINVAL; + goto cleanup; + } + + adapter = device->adapter; + ret = dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter = NULL; + goto cleanup; + } + + DXG_TRACE("Fence value: %lld", args.fence.fence_value); + ret = dxgvmb_send_wait_sync_object_gpu(process, adapter, + args.context, args.object_count, + args.object_array, + &args.fence.fence_value, true); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_waitforsynchronizationobjectfromcpu args; + struct dxgdevice *device = NULL; + struct dxgadapter *adapter = NULL; + struct eventfd_ctx *event = NULL; + struct dxghosteventcpu host_event = { }; + struct dxghosteventcpu *async_host_event = NULL; + struct completion local_event = { }; + u64 event_id = 0; + int ret; + bool host_event_added = false; + + ret = copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret = -EINVAL; + goto cleanup; + } + + if (args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE || + args.object_count == 0) { + ret = -EINVAL; + goto cleanup; + } + + if (args.async_event) { + async_host_event = kzalloc(sizeof(*async_host_event), + GFP_KERNEL); + if (async_host_event == NULL) { + ret = -EINVAL; + goto cleanup; + } + async_host_event->process = process; + event = eventfd_ctx_fdget((int)args.async_event); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event = NULL; + ret = -EINVAL; + goto cleanup; + } + async_host_event->cpu_event = event; + async_host_event->hdr.event_id = dxgglobal_new_host_event_id(); + async_host_event->destroy_after_signal = true; + async_host_event->hdr.event_type = dxghostevent_cpu_event; + dxgglobal_add_host_event(&async_host_event->hdr); + event_id = async_host_event->hdr.event_id; + host_event_added = true; + } else { + init_completion(&local_event); + host_event.completion_event = &local_event; + host_event.hdr.event_id = dxgglobal_new_host_event_id(); + host_event.hdr.event_type = dxghostevent_cpu_event; + dxgglobal_add_host_event(&host_event.hdr); + event_id = host_event.hdr.event_id; + } + + device = dxgprocess_device_by_handle(process, args.device); + if (device == NULL) { + ret = -EINVAL; + goto cleanup; + } + + adapter = device->adapter; + ret = dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter = NULL; + goto cleanup; + } + + ret = dxgvmb_send_wait_sync_object_cpu(process, adapter, + &args, event_id); + if (ret < 0) + goto cleanup; + + if (args.async_event == 0) { + dxgadapter_release_lock_shared(adapter); + adapter = NULL; + ret = wait_for_completion_interruptible(&local_event); + if (ret) { + DXG_ERR("wait_completion_interruptible: %d", + ret); + ret = -ERESTARTSYS; + } + } + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + if (host_event.hdr.event_id) + dxgglobal_remove_host_event(&host_event.hdr); + if (ret < 0) { + if (host_event_added) { + async_host_event = (struct dxghosteventcpu *) + dxgglobal_get_host_event(event_id); + if (async_host_event) { + if (async_host_event->hdr.event_type == + dxghostevent_cpu_event) { + eventfd_ctx_put(event); + event = NULL; + kfree(async_host_event); + async_host_event = NULL; + } else { + DXG_ERR("Invalid event type"); + DXGKRNL_ASSERT(0); + } + } + } + if (event) + eventfd_ctx_put(event); + if (async_host_event) + kfree(async_host_event); + } + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_wait_sync_object_gpu(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_waitforsynchronizationobjectfromgpu args; + struct dxgcontext *context = NULL; + struct d3dkmthandle device_handle = {}; + struct dxgdevice *device = NULL; + struct dxgadapter *adapter = NULL; + struct dxgsyncobject *syncobj = NULL; + struct d3dkmthandle *objects = NULL; + u32 object_size; + u64 *fences = NULL; + int ret; + enum hmgrentry_type syncobj_type = HMGRENTRY_TYPE_FREE; + bool monitored_fence = false; + + ret = copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret = -EINVAL; + goto cleanup; + } + + if (args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE || + args.object_count == 0) { + DXG_ERR("Invalid object count: %d", args.object_count); + ret = -EINVAL; + goto cleanup; + } + + object_size = sizeof(struct d3dkmthandle) * args.object_count; + objects = vzalloc(object_size); + if (objects == NULL) { + ret = -ENOMEM; + goto cleanup; + } + ret = copy_from_user(objects, args.objects, object_size); + if (ret) { + DXG_ERR("failed to copy objects"); + ret = -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); + context = hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (context) { + device_handle = context->device_handle; + syncobj_type = + hmgrtable_get_object_type(&process->handle_table, + objects[0]); + } + if (device_handle.v == 0) { + DXG_ERR("Invalid context handle: %x", args.context.v); + ret = -EINVAL; + } else { + if (syncobj_type == HMGRENTRY_TYPE_MONITOREDFENCE) { + monitored_fence = true; + } else if (syncobj_type == HMGRENTRY_TYPE_DXGSYNCOBJECT) { + syncobj = + hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + objects[0]); + if (syncobj == NULL) { + DXG_ERR("Invalid syncobj: %x", + objects[0].v); + ret = -EINVAL; + } else { + monitored_fence = syncobj->monitored_fence; + } + } else { + DXG_ERR("Invalid syncobj type: %x", + objects[0].v); + ret = -EINVAL; + } + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED); + + if (ret < 0) + goto cleanup; + + if (monitored_fence) { + object_size = sizeof(u64) * args.object_count; + fences = vzalloc(object_size); + if (fences == NULL) { + ret = -ENOMEM; + goto cleanup; + } + ret = copy_from_user(fences, args.monitored_fence_values, + object_size); + if (ret) { + DXG_ERR("failed to copy fences"); + ret = -EINVAL; + goto cleanup; + } + } else { + fences = &args.fence_value; + } + + device = dxgprocess_device_by_handle(process, device_handle); + if (device == NULL) { + ret = -EINVAL; + goto cleanup; + } + + adapter = device->adapter; + ret = dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter = NULL; + goto cleanup; + } + + ret = dxgvmb_send_wait_sync_object_gpu(process, adapter, + args.context, args.object_count, + objects, fences, + !monitored_fence); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + if (objects) + vfree(objects); + if (fences && fences != &args.fence_value) + vfree(fences); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static struct ioctl_desc ioctls[] = { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -1485,8 +2164,8 @@ static struct ioctl_desc ioctls[] = { /* 0x0e */ {}, /* 0x0f */ {}, /* 0x10 */ {dxgkio_create_sync_object, LX_DXCREATESYNCHRONIZATIONOBJECT}, -/* 0x11 */ {}, -/* 0x12 */ {}, +/* 0x11 */ {dxgkio_signal_sync_object, LX_DXSIGNALSYNCHRONIZATIONOBJECT}, +/* 0x12 */ {dxgkio_wait_sync_object, LX_DXWAITFORSYNCHRONIZATIONOBJECT}, /* 0x13 */ {dxgkio_destroy_allocation, LX_DXDESTROYALLOCATION2}, /* 0x14 */ {dxgkio_enum_adapters, LX_DXENUMADAPTERS2}, /* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER}, @@ -1517,17 +2196,22 @@ static struct ioctl_desc ioctls[] = { /* 0x2e */ {}, /* 0x2f */ {}, /* 0x30 */ {}, -/* 0x31 */ {}, -/* 0x32 */ {}, -/* 0x33 */ {}, +/* 0x31 */ {dxgkio_signal_sync_object_cpu, + LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU}, +/* 0x32 */ {dxgkio_signal_sync_object_gpu, + LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU}, +/* 0x33 */ {dxgkio_signal_sync_object_gpu2, + LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2}, /* 0x34 */ {}, /* 0x35 */ {}, /* 0x36 */ {}, /* 0x37 */ {}, /* 0x38 */ {}, /* 0x39 */ {}, -/* 0x3a */ {}, -/* 0x3b */ {}, +/* 0x3a */ {dxgkio_wait_sync_object_cpu, + LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU}, +/* 0x3b */ {dxgkio_wait_sync_object_gpu, + LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU}, /* 0x3c */ {}, /* 0x3d */ {}, /* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3}, diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h index 111111111111..222222222222 100644 --- a/drivers/hv/dxgkrnl/misc.h +++ b/drivers/hv/dxgkrnl/misc.h @@ -25,6 +25,8 @@ extern const struct d3dkmthandle zerohandle; * The locks here are in the order from lowest to highest. * When a lower lock is held, the higher lock should not be acquired. * + * device_list_mutex + * host_event_list_mutex * channel_lock (VMBus channel lock) * fd_mutex * plistmutex (process list mutex) diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 111111111111..222222222222 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -60,6 +60,9 @@ struct winluid { #define D3DKMT_CREATEALLOCATION_MAX 1024 #define D3DKMT_ADAPTERS_MAX 64 +#define D3DDDI_MAX_BROADCAST_CONTEXT 64 +#define D3DDDI_MAX_OBJECT_WAITED_ON 32 +#define D3DDDI_MAX_OBJECT_SIGNALED 32 struct d3dkmt_adapterinfo { struct d3dkmthandle adapter_handle; @@ -343,6 +346,148 @@ struct d3dkmt_createsynchronizationobject2 { __u32 reserved1; }; +struct d3dkmt_waitforsynchronizationobject2 { + struct d3dkmthandle context; + __u32 object_count; + struct d3dkmthandle object_array[D3DDDI_MAX_OBJECT_WAITED_ON]; + union { + struct { + __u64 fence_value; + } fence; + __u64 reserved[8]; + }; +}; + +struct d3dddicb_signalflags { + union { + struct { + __u32 signal_at_submission:1; + __u32 enqueue_cpu_event:1; + __u32 allow_fence_rewind:1; + __u32 reserved:28; + __u32 DXGK_SIGNAL_FLAG_INTERNAL0:1; + }; + __u32 value; + }; +}; + +struct d3dkmt_signalsynchronizationobject2 { + struct d3dkmthandle context; + __u32 object_count; + struct d3dkmthandle object_array[D3DDDI_MAX_OBJECT_SIGNALED]; + struct d3dddicb_signalflags flags; + __u32 context_count; + struct d3dkmthandle contexts[D3DDDI_MAX_BROADCAST_CONTEXT]; + union { + struct { + __u64 fence_value; + } fence; + __u64 cpu_event_handle; + __u64 reserved[8]; + }; +}; + +struct d3dddi_waitforsynchronizationobjectfromcpu_flags { + union { + struct { + __u32 wait_any:1; + __u32 reserved:31; + }; + __u32 value; + }; +}; + +struct d3dkmt_waitforsynchronizationobjectfromcpu { + struct d3dkmthandle device; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; + __u64 *fence_values; +#else + __u64 objects; + __u64 fence_values; +#endif + __u64 async_event; + struct d3dddi_waitforsynchronizationobjectfromcpu_flags flags; +}; + +struct d3dkmt_signalsynchronizationobjectfromcpu { + struct d3dkmthandle device; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; + __u64 *fence_values; +#else + __u64 objects; + __u64 fence_values; +#endif + struct d3dddicb_signalflags flags; +}; + +struct d3dkmt_waitforsynchronizationobjectfromgpu { + struct d3dkmthandle context; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; +#else + __u64 objects; +#endif + union { +#ifdef __KERNEL__ + __u64 *monitored_fence_values; +#else + __u64 monitored_fence_values; +#endif + __u64 fence_value; + __u64 reserved[8]; + }; +}; + +struct d3dkmt_signalsynchronizationobjectfromgpu { + struct d3dkmthandle context; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; +#else + __u64 objects; +#endif + union { +#ifdef __KERNEL__ + __u64 *monitored_fence_values; +#else + __u64 monitored_fence_values; +#endif + __u64 reserved[8]; + }; +}; + +struct d3dkmt_signalsynchronizationobjectfromgpu2 { + __u32 object_count; + __u32 reserved1; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; +#else + __u64 objects; +#endif + struct d3dddicb_signalflags flags; + __u32 context_count; +#ifdef __KERNEL__ + struct d3dkmthandle *contexts; +#else + __u64 contexts; +#endif + union { + __u64 fence_value; + __u64 cpu_event_handle; +#ifdef __KERNEL__ + __u64 *monitored_fence_values; +#else + __u64 monitored_fence_values; +#endif + __u64 reserved[8]; + }; +}; + struct d3dkmt_destroysynchronizationobject { struct d3dkmthandle sync_object; }; @@ -576,6 +721,10 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) #define LX_DXCREATESYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x10, struct d3dkmt_createsynchronizationobject2) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECT \ + _IOWR(0x47, 0x11, struct d3dkmt_signalsynchronizationobject2) +#define LX_DXWAITFORSYNCHRONIZATIONOBJECT \ + _IOWR(0x47, 0x12, struct d3dkmt_waitforsynchronizationobject2) #define LX_DXDESTROYALLOCATION2 \ _IOWR(0x47, 0x13, struct d3dkmt_destroyallocation2) #define LX_DXENUMADAPTERS2 \ @@ -586,6 +735,16 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) #define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ + _IOWR(0x47, 0x31, struct d3dkmt_signalsynchronizationobjectfromcpu) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU \ + _IOWR(0x47, 0x32, struct d3dkmt_signalsynchronizationobjectfromgpu) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2 \ + _IOWR(0x47, 0x33, struct d3dkmt_signalsynchronizationobjectfromgpu2) +#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU \ + _IOWR(0x47, 0x3a, struct d3dkmt_waitforsynchronizationobjectfromcpu) +#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU \ + _IOWR(0x47, 0x3b, struct d3dkmt_waitforsynchronizationobjectfromgpu) #define LX_DXENUMADAPTERS3 \ _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) -- Armbian