* [PATCH v1 2/9] drivers: hv: dxgkrnl: Open device object, adapter enumeration, dxgdevice, dxgcontext creation
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-13 7:41 ` Greg KH
2022-01-13 7:44 ` kernel test robot
2022-01-12 19:55 ` [PATCH v1 3/9] drivers: hv: dxgkrnl: Implement creation/destruction of GPU allocations/resources Iouri Tarassov
` (8 subsequent siblings)
9 siblings, 2 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
- Handle opening of the device (/dev/dxg) file object and creation of
dxgprocess. dxgprocess is created for each process, which opens /dev/dxg.
dxgprocess is ref counted, so the exicting dxgprocess objects is used for
a process, which opens the device object multiple time.
dxgprocess is destroyed when the device object is closed.
- Implement ioctls for virtual GPU adapter enumeration:
LX_DXENUMADAPTERS2, LX_DXENUMADAPTERS3
The IOCTLs return a d3dkmt handle for each enumerated adapter.
- Implement ioctl to query adapter information:
LX_DXQUERYADAPTERINFO.
- Implement ioctls to open and closet a dxgadapter object:
LX_DXOPENADAPTERFROMLUID, LX_DXCLOSEADAPTER
Note that dxgadapter is opened when LX_DXENUMADAPTERS2, LX_DXENUMADAPTERS3
are called.
- Implement ioctls for dxgdevice and dxgcontext creation/destruction:
LX_DXCREATEDEVICE, LX_DXCREATECONTEXT, LX_DXCREATECONTEXTVIRTUAL,
LX_DXDESTROYCONTEXT, LX_DXCREATEHWCONTEXT, LX_DXDESTROYDEVICE,
LX_DXDESTROYHWCONTEXT
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 494 +++++++++++++++++++
drivers/hv/dxgkrnl/dxgkrnl.h | 4 -
drivers/hv/dxgkrnl/dxgprocess.c | 316 ++++++++++++-
drivers/hv/dxgkrnl/dxgvmbus.c | 314 ++++++++++++
drivers/hv/dxgkrnl/hmgr.c | 509 ++++++++++++++++++++
drivers/hv/dxgkrnl/ioctl.c | 812 +++++++++++++++++++++++++++++++-
6 files changed, 2436 insertions(+), 13 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index 164d91e68552..b461d6b6f55e 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -149,6 +149,24 @@ bool dxgadapter_is_active(struct dxgadapter *adapter)
return adapter->adapter_state == DXGADAPTER_STATE_ACTIVE;
}
+/* Protected by dxgglobal_acquire_process_adapter_lock */
+void dxgadapter_add_process(struct dxgadapter *adapter,
+ struct dxgprocess_adapter *process_info)
+{
+ dev_dbg(dxgglobaldev, "%s %p %p", __func__, adapter, process_info);
+ list_add_tail(&process_info->adapter_process_list_entry,
+ &adapter->adapter_process_list_head);
+}
+
+void dxgadapter_remove_process(struct dxgprocess_adapter *process_info)
+{
+ dev_dbg(dxgglobaldev, "%s %p %p", __func__,
+ process_info->adapter, process_info);
+ list_del(&process_info->adapter_process_list_entry);
+ process_info->adapter_process_list_entry.next = NULL;
+ process_info->adapter_process_list_entry.prev = NULL;
+}
+
int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter)
{
down_write(&adapter->core_lock);
@@ -183,7 +201,483 @@ void dxgadapter_release_lock_shared(struct dxgadapter *adapter)
up_read(&adapter->core_lock);
}
+struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
+ struct dxgprocess *process)
+{
+ struct dxgdevice *device = vzalloc(sizeof(struct dxgdevice));
+ int ret;
+
+ if (device) {
+ kref_init(&device->device_kref);
+ device->adapter = adapter;
+ device->process = process;
+ kref_get(&adapter->adapter_kref);
+ INIT_LIST_HEAD(&device->context_list_head);
+ INIT_LIST_HEAD(&device->alloc_list_head);
+ INIT_LIST_HEAD(&device->resource_list_head);
+ init_rwsem(&device->device_lock);
+ init_rwsem(&device->context_list_lock);
+ init_rwsem(&device->alloc_list_lock);
+ INIT_LIST_HEAD(&device->pqueue_list_head);
+ INIT_LIST_HEAD(&device->syncobj_list_head);
+ device->object_state = DXGOBJECTSTATE_CREATED;
+ device->execution_state = _D3DKMT_DEVICEEXECUTION_ACTIVE;
+
+ ret = dxgprocess_adapter_add_device(process, adapter, device);
+ if (ret < 0) {
+ kref_put(&device->device_kref, dxgdevice_release);
+ device = NULL;
+ }
+ }
+ return device;
+}
+
+void dxgdevice_stop(struct dxgdevice *device)
+{
+ struct dxgallocation *alloc;
+ struct dxgpagingqueue *pqueue;
+ struct dxgsyncobject *syncobj;
+
+ dev_dbg(dxgglobaldev, "%s: %p", __func__, device);
+ dxgdevice_acquire_alloc_list_lock(device);
+ list_for_each_entry(alloc, &device->alloc_list_head, alloc_list_entry) {
+ dxgallocation_stop(alloc);
+ }
+ dxgdevice_release_alloc_list_lock(device);
+
+ hmgrtable_lock(&device->process->handle_table, DXGLOCK_EXCL);
+ list_for_each_entry(pqueue, &device->pqueue_list_head,
+ pqueue_list_entry) {
+ dxgpagingqueue_stop(pqueue);
+ }
+ list_for_each_entry(syncobj, &device->syncobj_list_head,
+ syncobj_list_entry) {
+ dxgsyncobject_stop(syncobj);
+ }
+ hmgrtable_unlock(&device->process->handle_table, DXGLOCK_EXCL);
+ dev_dbg(dxgglobaldev, "%s: end %p\n", __func__, device);
+}
+
+void dxgdevice_mark_destroyed(struct dxgdevice *device)
+{
+ down_write(&device->device_lock);
+ device->object_state = DXGOBJECTSTATE_DESTROYED;
+ up_write(&device->device_lock);
+}
+
+void dxgdevice_destroy(struct dxgdevice *device)
+{
+ struct dxgprocess *process = device->process;
+ struct dxgadapter *adapter = device->adapter;
+ struct d3dkmthandle device_handle = {};
+
+ dev_dbg(dxgglobaldev, "%s: %p\n", __func__, device);
+
+ down_write(&device->device_lock);
+
+ if (device->object_state != DXGOBJECTSTATE_ACTIVE)
+ goto cleanup;
+
+ device->object_state = DXGOBJECTSTATE_DESTROYED;
+
+ dxgdevice_stop(device);
+
+ dxgdevice_acquire_alloc_list_lock(device);
+
+ while (!list_empty(&device->syncobj_list_head)) {
+ struct dxgsyncobject *syncobj =
+ list_first_entry(&device->syncobj_list_head,
+ struct dxgsyncobject,
+ syncobj_list_entry);
+ list_del(&syncobj->syncobj_list_entry);
+ syncobj->syncobj_list_entry.next = NULL;
+ dxgdevice_release_alloc_list_lock(device);
+
+ dxgsyncobject_destroy(process, syncobj);
+
+ dxgdevice_acquire_alloc_list_lock(device);
+ }
+
+ {
+ struct dxgallocation *alloc;
+ struct dxgallocation *tmp;
+
+ dev_dbg(dxgglobaldev, "destroying allocations\n");
+ list_for_each_entry_safe(alloc, tmp, &device->alloc_list_head,
+ alloc_list_entry) {
+ dxgallocation_destroy(alloc);
+ }
+ }
+
+ {
+ struct dxgresource *resource;
+ struct dxgresource *tmp;
+
+ dev_dbg(dxgglobaldev, "destroying resources\n");
+ list_for_each_entry_safe(resource, tmp,
+ &device->resource_list_head,
+ resource_list_entry) {
+ dxgresource_destroy(resource);
+ }
+ }
+
+ dxgdevice_release_alloc_list_lock(device);
+
+ {
+ struct dxgcontext *context;
+ struct dxgcontext *tmp;
+
+ dev_dbg(dxgglobaldev, "destroying contexts\n");
+ dxgdevice_acquire_context_list_lock(device);
+ list_for_each_entry_safe(context, tmp,
+ &device->context_list_head,
+ context_list_entry) {
+ dxgcontext_destroy(process, context);
+ }
+ dxgdevice_release_context_list_lock(device);
+ }
+
+ {
+ struct dxgpagingqueue *tmp;
+ struct dxgpagingqueue *pqueue;
+
+ dev_dbg(dxgglobaldev, "destroying paging queues\n");
+ list_for_each_entry_safe(pqueue, tmp, &device->pqueue_list_head,
+ pqueue_list_entry) {
+ dxgpagingqueue_destroy(pqueue);
+ }
+ }
+
+ /* Guest handles need to be released before the host handles */
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ if (device->handle_valid) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGDEVICE, device->handle);
+ device_handle = device->handle;
+ device->handle_valid = 0;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (device_handle.v) {
+ up_write(&device->device_lock);
+ if (dxgadapter_acquire_lock_shared(adapter) == 0) {
+ dxgvmb_send_destroy_device(adapter, process,
+ device_handle);
+ dxgadapter_release_lock_shared(adapter);
+ }
+ down_write(&device->device_lock);
+ }
+
+cleanup:
+
+ if (device->adapter) {
+ dxgprocess_adapter_remove_device(device);
+ kref_put(&device->adapter->adapter_kref, dxgadapter_release);
+ }
+
+ up_write(&device->device_lock);
+
+ kref_put(&device->device_kref, dxgdevice_release);
+ dev_dbg(dxgglobaldev, "dxgdevice_destroy_end\n");
+}
+
+int dxgdevice_acquire_lock_shared(struct dxgdevice *device)
+{
+ down_read(&device->device_lock);
+ if (!dxgdevice_is_active(device)) {
+ up_read(&device->device_lock);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+void dxgdevice_release_lock_shared(struct dxgdevice *device)
+{
+ up_read(&device->device_lock);
+}
+
+bool dxgdevice_is_active(struct dxgdevice *device)
+{
+ return device->object_state == DXGOBJECTSTATE_ACTIVE;
+}
+
+void dxgdevice_acquire_context_list_lock(struct dxgdevice *device)
+{
+ down_write(&device->context_list_lock);
+}
+
+void dxgdevice_release_context_list_lock(struct dxgdevice *device)
+{
+ up_write(&device->context_list_lock);
+}
+
+void dxgdevice_acquire_alloc_list_lock(struct dxgdevice *device)
+{
+ down_write(&device->alloc_list_lock);
+}
+
+void dxgdevice_release_alloc_list_lock(struct dxgdevice *device)
+{
+ up_write(&device->alloc_list_lock);
+}
+
+void dxgdevice_acquire_alloc_list_lock_shared(struct dxgdevice *device)
+{
+ down_read(&device->alloc_list_lock);
+}
+
+void dxgdevice_release_alloc_list_lock_shared(struct dxgdevice *device)
+{
+ up_read(&device->alloc_list_lock);
+}
+
+void dxgdevice_add_context(struct dxgdevice *device, struct dxgcontext *context)
+{
+ down_write(&device->context_list_lock);
+ list_add_tail(&context->context_list_entry, &device->context_list_head);
+ up_write(&device->context_list_lock);
+}
+
+void dxgdevice_remove_context(struct dxgdevice *device,
+ struct dxgcontext *context)
+{
+ if (context->context_list_entry.next) {
+ list_del(&context->context_list_entry);
+ context->context_list_entry.next = NULL;
+ }
+}
+
+void dxgdevice_release(struct kref *refcount)
+{
+ struct dxgdevice *device;
+
+ device = container_of(refcount, struct dxgdevice, device_kref);
+ vfree(device);
+}
+
+struct dxgcontext *dxgcontext_create(struct dxgdevice *device)
+{
+ struct dxgcontext *context = vzalloc(sizeof(struct dxgcontext));
+
+ if (context) {
+ kref_init(&context->context_kref);
+ context->device = device;
+ context->process = device->process;
+ context->device_handle = device->handle;
+ kref_get(&device->device_kref);
+ INIT_LIST_HEAD(&context->hwqueue_list_head);
+ init_rwsem(&context->hwqueue_list_lock);
+ dxgdevice_add_context(device, context);
+ context->object_state = DXGOBJECTSTATE_ACTIVE;
+ }
+ return context;
+}
+
+/*
+ * Called when the device context list lock is held
+ */
+void dxgcontext_destroy(struct dxgprocess *process, struct dxgcontext *context)
+{
+ struct dxghwqueue *hwqueue;
+ struct dxghwqueue *tmp;
+
+ dev_dbg(dxgglobaldev, "%s %p\n", __func__, context);
+ context->object_state = DXGOBJECTSTATE_DESTROYED;
+ if (context->device) {
+ if (context->handle.v) {
+ hmgrtable_free_handle_safe(&process->handle_table,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ context->handle);
+ }
+ dxgdevice_remove_context(context->device, context);
+ kref_put(&context->device->device_kref, dxgdevice_release);
+ }
+ list_for_each_entry_safe(hwqueue, tmp, &context->hwqueue_list_head,
+ hwqueue_list_entry) {
+ dxghwqueue_destroy(process, hwqueue);
+ }
+ kref_put(&context->context_kref, dxgcontext_release);
+}
+
+void dxgcontext_destroy_safe(struct dxgprocess *process,
+ struct dxgcontext *context)
+{
+ struct dxgdevice *device = context->device;
+
+ dxgdevice_acquire_context_list_lock(device);
+ dxgcontext_destroy(process, context);
+ dxgdevice_release_context_list_lock(device);
+}
+
+bool dxgcontext_is_active(struct dxgcontext *context)
+{
+ return context->object_state == DXGOBJECTSTATE_ACTIVE;
+}
+
+void dxgcontext_release(struct kref *refcount)
+{
+ struct dxgcontext *context;
+
+ context = container_of(refcount, struct dxgcontext, context_kref);
+ vfree(context);
+}
+
+struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
+ struct dxgadapter *adapter)
+{
+ struct dxgprocess_adapter *adapter_info;
+
+ adapter_info = vzalloc(sizeof(*adapter_info));
+ if (adapter_info) {
+ if (kref_get_unless_zero(&adapter->adapter_kref) == 0) {
+ pr_err("failed to acquire adapter reference");
+ goto cleanup;
+ }
+ adapter_info->adapter = adapter;
+ adapter_info->process = process;
+ adapter_info->refcount = 1;
+ mutex_init(&adapter_info->device_list_mutex);
+ INIT_LIST_HEAD(&adapter_info->device_list_head);
+ list_add_tail(&adapter_info->process_adapter_list_entry,
+ &process->process_adapter_list_head);
+ dxgadapter_add_process(adapter, adapter_info);
+ }
+ return adapter_info;
+cleanup:
+ if (adapter_info)
+ vfree(adapter_info);
+ return NULL;
+}
+
void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info)
+{
+ struct dxgdevice *device;
+
+ mutex_lock(&adapter_info->device_list_mutex);
+ list_for_each_entry(device, &adapter_info->device_list_head,
+ device_list_entry) {
+ dxgdevice_stop(device);
+ }
+ mutex_unlock(&adapter_info->device_list_mutex);
+}
+
+void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info)
+{
+ struct dxgdevice *device;
+
+ mutex_lock(&adapter_info->device_list_mutex);
+ while (!list_empty(&adapter_info->device_list_head)) {
+ device = list_first_entry(&adapter_info->device_list_head,
+ struct dxgdevice, device_list_entry);
+ list_del(&device->device_list_entry);
+ device->device_list_entry.next = NULL;
+ mutex_unlock(&adapter_info->device_list_mutex);
+ dxgdevice_destroy(device);
+ mutex_lock(&adapter_info->device_list_mutex);
+ }
+ mutex_unlock(&adapter_info->device_list_mutex);
+
+ dxgadapter_remove_process(adapter_info);
+ kref_put(&adapter_info->adapter->adapter_kref, dxgadapter_release);
+ list_del(&adapter_info->process_adapter_list_entry);
+ vfree(adapter_info);
+}
+
+/*
+ * Must be called when dxgglobal::process_adapter_mutex is held
+ */
+void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter_info)
+{
+ dev_dbg(dxgglobaldev, "%s %p %d",
+ __func__, adapter_info, adapter_info->refcount);
+ adapter_info->refcount--;
+ if (adapter_info->refcount == 0)
+ dxgprocess_adapter_destroy(adapter_info);
+}
+
+int dxgprocess_adapter_add_device(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct dxgdevice *device)
+{
+ struct dxgprocess_adapter *entry;
+ struct dxgprocess_adapter *adapter_info = NULL;
+ int ret = 0;
+
+ dxgglobal_acquire_process_adapter_lock();
+
+ list_for_each_entry(entry, &process->process_adapter_list_head,
+ process_adapter_list_entry) {
+ if (entry->adapter == adapter) {
+ adapter_info = entry;
+ break;
+ }
+ }
+ if (adapter_info == NULL) {
+ pr_err("failed to find process adapter info\n");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ mutex_lock(&adapter_info->device_list_mutex);
+ list_add_tail(&device->device_list_entry,
+ &adapter_info->device_list_head);
+ device->adapter_info = adapter_info;
+ mutex_unlock(&adapter_info->device_list_mutex);
+
+cleanup:
+
+ dxgglobal_release_process_adapter_lock();
+ return ret;
+}
+
+void dxgprocess_adapter_remove_device(struct dxgdevice *device)
+{
+ dev_dbg(dxgglobaldev, "%s %p\n", __func__, device);
+ mutex_lock(&device->adapter_info->device_list_mutex);
+ if (device->device_list_entry.next) {
+ list_del(&device->device_list_entry);
+ device->device_list_entry.next = NULL;
+ }
+ mutex_unlock(&device->adapter_info->device_list_mutex);
+}
+
+void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwqueue)
+{
+ /* Placeholder */
+}
+
+void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue)
{
/* Placeholder */
}
+
+void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue)
+{
+ /* Placeholder */
+}
+
+void dxgallocation_destroy(struct dxgallocation *alloc)
+{
+ /* Placeholder */
+}
+
+void dxgallocation_stop(struct dxgallocation *alloc)
+{
+ /* Placeholder */
+}
+
+void dxgresource_destroy(struct dxgresource *resource)
+{
+ /* Placeholder */
+}
+
+void dxgsyncobject_destroy(struct dxgprocess *process,
+ struct dxgsyncobject *syncobj)
+{
+ /* Placeholder */
+}
+
+void dxgsyncobject_stop(struct dxgsyncobject *syncobj)
+{
+ /* Placeholder */
+}
+
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 412ff6a5950a..269391319f56 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -723,10 +723,6 @@ long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2);
long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2);
int dxg_unmap_iospace(void *va, u32 size);
-int dxg_copy_from_user(void *to, const void __user *from,
- unsigned long len);
-int dxg_copy_to_user(void __user *to, const void *from,
- unsigned long len);
static inline void guid_to_luid(guid_t *guid, struct winluid *luid)
{
*luid = *(struct winluid *)&guid->b[0];
diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgprocess.c
index 4b57ecf47bb3..b05df641dc77 100644
--- a/drivers/hv/dxgkrnl/dxgprocess.c
+++ b/drivers/hv/dxgkrnl/dxgprocess.c
@@ -4,7 +4,7 @@
* Copyright (c) 2019, Microsoft Corporation.
*
* Author:
- * Iouri Tarassov <iourit@microsoft.com>
+ * Iouri Tarassov <iourit@linux.microsoft.com>
*
* Dxgkrnl Graphics Driver
* DXGPROCESS implementation
@@ -22,16 +22,322 @@
*/
struct dxgprocess *dxgprocess_create(void)
{
- /* Placeholder */
- return NULL;
+ struct dxgprocess *process;
+ int ret;
+
+ process = vzalloc(sizeof(struct dxgprocess));
+ if (process != NULL) {
+ dev_dbg(dxgglobaldev, "new dxgprocess created\n");
+ process->process = current;
+ process->pid = current->pid;
+ process->tgid = current->tgid;
+ mutex_init(&process->process_mutex);
+ ret = dxgvmb_send_create_process(process);
+ if (ret < 0) {
+ dev_dbg(dxgglobaldev, "send_create_process failed\n");
+ vfree(process);
+ process = NULL;
+ } else {
+ INIT_LIST_HEAD(&process->plistentry);
+ kref_init(&process->process_kref);
+
+ mutex_lock(&dxgglobal->plistmutex);
+ list_add_tail(&process->plistentry,
+ &dxgglobal->plisthead);
+ mutex_unlock(&dxgglobal->plistmutex);
+
+ hmgrtable_init(&process->handle_table, process);
+ hmgrtable_init(&process->local_handle_table, process);
+ INIT_LIST_HEAD(&process->process_adapter_list_head);
+ }
+ }
+ return process;
}
void dxgprocess_destroy(struct dxgprocess *process)
{
- /* Placeholder */
+ int i;
+ enum hmgrentry_type t;
+ struct d3dkmthandle h;
+ void *o;
+ struct dxgsyncobject *syncobj;
+ struct dxgprocess_adapter *entry;
+ struct dxgprocess_adapter *tmp;
+
+ /* Destroy all adapter state */
+ dxgglobal_acquire_process_adapter_lock();
+ list_for_each_entry_safe(entry, tmp,
+ &process->process_adapter_list_head,
+ process_adapter_list_entry) {
+ dxgprocess_adapter_destroy(entry);
+ }
+ dxgglobal_release_process_adapter_lock();
+
+ i = 0;
+ while (hmgrtable_next_entry(&process->local_handle_table,
+ &i, &t, &h, &o)) {
+ switch (t) {
+ case HMGRENTRY_TYPE_DXGADAPTER:
+ dxgprocess_close_adapter(process, h);
+ break;
+ default:
+ pr_err("invalid entry in local handle table %d", t);
+ break;
+ }
+ }
+
+ i = 0;
+ while (hmgrtable_next_entry(&process->handle_table, &i, &t, &h, &o)) {
+ switch (t) {
+ case HMGRENTRY_TYPE_DXGSYNCOBJECT:
+ dev_dbg(dxgglobaldev, "Destroy syncobj: %p %d", o, i);
+ syncobj = o;
+ syncobj->handle.v = 0;
+ dxgsyncobject_destroy(process, syncobj);
+ break;
+ default:
+ pr_err("invalid entry in handle table %d", t);
+ break;
+ }
+ }
+
+ hmgrtable_destroy(&process->handle_table);
+ hmgrtable_destroy(&process->local_handle_table);
+
+ for (i = 0; i < 2; i++) {
+ if (process->test_handle_table[i]) {
+ hmgrtable_destroy(process->test_handle_table[i]);
+ vfree(process->test_handle_table[i]);
+ process->test_handle_table[i] = NULL;
+ }
+ }
}
void dxgprocess_release(struct kref *refcount)
{
- /* Placeholder */
+ struct dxgprocess *process;
+
+ process = container_of(refcount, struct dxgprocess, process_kref);
+
+ mutex_lock(&dxgglobal->plistmutex);
+ list_del(&process->plistentry);
+ process->plistentry.next = NULL;
+ mutex_unlock(&dxgglobal->plistmutex);
+
+ dxgprocess_destroy(process);
+
+ if (process->host_handle.v)
+ dxgvmb_send_destroy_process(process->host_handle);
+ vfree(process);
+}
+
+struct dxgprocess_adapter *dxgprocess_get_adapter_info(struct dxgprocess
+ *process,
+ struct dxgadapter
+ *adapter)
+{
+ struct dxgprocess_adapter *entry;
+
+ list_for_each_entry(entry, &process->process_adapter_list_head,
+ process_adapter_list_entry) {
+ if (adapter == entry->adapter) {
+ dev_dbg(dxgglobaldev, "Found process info %p", entry);
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Dxgprocess takes references on dxgadapter and dxgprocess_adapter.
+ */
+int dxgprocess_open_adapter(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle *h)
+{
+ int ret = 0;
+ struct dxgprocess_adapter *adapter_info;
+ struct d3dkmthandle handle;
+
+ h->v = 0;
+ adapter_info = dxgprocess_get_adapter_info(process, adapter);
+ if (adapter_info == NULL) {
+ dev_dbg(dxgglobaldev, "creating new process adapter info\n");
+ adapter_info = dxgprocess_adapter_create(process, adapter);
+ if (adapter_info == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ } else {
+ adapter_info->refcount++;
+ }
+
+ handle = hmgrtable_alloc_handle_safe(&process->local_handle_table,
+ adapter, HMGRENTRY_TYPE_DXGADAPTER,
+ true);
+ if (handle.v) {
+ *h = handle;
+ } else {
+ pr_err("failed to create adapter handle\n");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+cleanup:
+
+ if (ret < 0) {
+ if (adapter_info) {
+ dxgglobal_acquire_process_adapter_lock();
+ dxgprocess_adapter_release(adapter_info);
+ dxgglobal_release_process_adapter_lock();
+ }
+ }
+
+ return ret;
+}
+
+int dxgprocess_close_adapter(struct dxgprocess *process,
+ struct d3dkmthandle handle)
+{
+ struct dxgadapter *adapter;
+ struct dxgprocess_adapter *adapter_info;
+ int ret = 0;
+
+ if (handle.v == 0)
+ return 0;
+
+ hmgrtable_lock(&process->local_handle_table, DXGLOCK_EXCL);
+ adapter = dxgprocess_get_adapter(process, handle);
+ if (adapter)
+ hmgrtable_free_handle(&process->local_handle_table,
+ HMGRENTRY_TYPE_DXGADAPTER, handle);
+ hmgrtable_unlock(&process->local_handle_table, DXGLOCK_EXCL);
+
+ if (adapter) {
+ adapter_info = dxgprocess_get_adapter_info(process, adapter);
+ if (adapter_info) {
+ dxgglobal_acquire_process_adapter_lock();
+ dxgprocess_adapter_release(adapter_info);
+ dxgglobal_release_process_adapter_lock();
+ } else {
+ ret = -EINVAL;
+ }
+ } else {
+ pr_err("%s failed %x", __func__, handle.v);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+struct dxgadapter *dxgprocess_get_adapter(struct dxgprocess *process,
+ struct d3dkmthandle handle)
+{
+ struct dxgadapter *adapter;
+
+ adapter = hmgrtable_get_object_by_type(&process->local_handle_table,
+ HMGRENTRY_TYPE_DXGADAPTER,
+ handle);
+ if (adapter == NULL)
+ pr_err("%s failed %x\n", __func__, handle.v);
+ return adapter;
+}
+
+/*
+ * Gets the adapter object from the process handle table.
+ * The adapter object is referenced.
+ * The function acquired the handle table lock shared.
+ */
+struct dxgadapter *dxgprocess_adapter_by_handle(struct dxgprocess *process,
+ struct d3dkmthandle handle)
+{
+ struct dxgadapter *adapter;
+
+ hmgrtable_lock(&process->local_handle_table, DXGLOCK_SHARED);
+ adapter = hmgrtable_get_object_by_type(&process->local_handle_table,
+ HMGRENTRY_TYPE_DXGADAPTER,
+ handle);
+ if (adapter == NULL)
+ pr_err("adapter_by_handle failed %x\n", handle.v);
+ else if (kref_get_unless_zero(&adapter->adapter_kref) == 0) {
+ pr_err("failed to acquire adapter reference\n");
+ adapter = NULL;
+ }
+ hmgrtable_unlock(&process->local_handle_table, DXGLOCK_SHARED);
+ return adapter;
+}
+
+struct dxgdevice *dxgprocess_device_by_object_handle(struct dxgprocess *process,
+ enum hmgrentry_type t,
+ struct d3dkmthandle handle)
+{
+ struct dxgdevice *device = NULL;
+ void *obj;
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED);
+ obj = hmgrtable_get_object_by_type(&process->handle_table, t, handle);
+ if (obj) {
+ struct d3dkmthandle device_handle = {};
+
+ switch (t) {
+ case HMGRENTRY_TYPE_DXGDEVICE:
+ device = obj;
+ break;
+ case HMGRENTRY_TYPE_DXGCONTEXT:
+ device_handle =
+ ((struct dxgcontext *)obj)->device_handle;
+ break;
+ case HMGRENTRY_TYPE_DXGPAGINGQUEUE:
+ device_handle =
+ ((struct dxgpagingqueue *)obj)->device_handle;
+ break;
+ case HMGRENTRY_TYPE_DXGHWQUEUE:
+ device_handle =
+ ((struct dxghwqueue *)obj)->device_handle;
+ break;
+ default:
+ pr_err("invalid handle type: %d\n", t);
+ break;
+ }
+ if (device == NULL)
+ device = hmgrtable_get_object_by_type(
+ &process->handle_table,
+ HMGRENTRY_TYPE_DXGDEVICE,
+ device_handle);
+ if (device)
+ if (kref_get_unless_zero(&device->device_kref) == 0)
+ device = NULL;
+ }
+ if (device == NULL)
+ pr_err("device_by_handle failed: %d %x\n", t, handle.v);
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED);
+ return device;
+}
+
+struct dxgdevice *dxgprocess_device_by_handle(struct dxgprocess *process,
+ struct d3dkmthandle handle)
+{
+ return dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGDEVICE,
+ handle);
+}
+
+void dxgprocess_ht_lock_shared_down(struct dxgprocess *process)
+{
+ hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED);
+}
+
+void dxgprocess_ht_lock_shared_up(struct dxgprocess *process)
+{
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED);
+}
+
+void dxgprocess_ht_lock_exclusive_down(struct dxgprocess *process)
+{
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+}
+
+void dxgprocess_ht_lock_exclusive_up(struct dxgprocess *process)
+{
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
}
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index f27150a6b8b1..13dc34214f50 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -448,6 +448,84 @@ int dxgvmb_send_set_iospace_region(u64 start, u64 len,
return ret;
}
+int dxgvmb_send_create_process(struct dxgprocess *process)
+{
+ int ret;
+ struct dxgkvmb_command_createprocess *command;
+ struct dxgkvmb_command_createprocess_return result = { 0 };
+ struct dxgvmbusmsg msg;
+ char s[WIN_MAX_PATH];
+ int i;
+
+ ret = init_message(&msg, NULL, process, sizeof(*command));
+ if (ret)
+ return ret;
+ command = (void *)msg.msg;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+
+ command_vm_to_host_init1(&command->hdr, DXGK_VMBCOMMAND_CREATEPROCESS);
+ command->process = process;
+ command->process_id = process->process->pid;
+ command->linux_process = 1;
+ s[0] = 0;
+ __get_task_comm(s, WIN_MAX_PATH, process->process);
+ for (i = 0; i < WIN_MAX_PATH; i++) {
+ command->process_name[i] = s[i];
+ if (s[i] == 0)
+ break;
+ }
+
+ ret = dxgvmb_send_sync_msg(&dxgglobal->channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0) {
+ pr_err("create_process failed %d", ret);
+ } else if (result.hprocess.v == 0) {
+ pr_err("create_process returned 0 handle");
+ ret = -ENOTRECOVERABLE;
+ } else {
+ process->host_handle = result.hprocess;
+ dev_dbg(dxgglobaldev, "create_process returned %x",
+ process->host_handle.v);
+ }
+
+ dxgglobal_release_channel_lock();
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_destroy_process(struct d3dkmthandle process)
+{
+ int ret;
+ struct dxgkvmb_command_destroyprocess *command;
+ struct dxgvmbusmsg msg;
+
+ ret = init_message(&msg, NULL, NULL, sizeof(*command));
+ if (ret)
+ return ret;
+ command = (void *)msg.msg;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+ command_vm_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_DESTROYPROCESS,
+ process);
+ ret = dxgvmb_send_sync_msg_ntstatus(&dxgglobal->channel,
+ msg.hdr, msg.size);
+ dxgglobal_release_channel_lock();
+
+cleanup:
+ free_message(&msg, NULL);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
/*
* Virtual GPU messages to the host
@@ -541,3 +619,239 @@ int dxgvmb_send_get_internal_adapter_info(struct dxgadapter *adapter)
dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
return ret;
}
+
+struct d3dkmthandle dxgvmb_send_create_device(struct dxgadapter *adapter,
+ struct dxgprocess *process,
+ struct d3dkmt_createdevice *args)
+{
+ int ret;
+ struct dxgkvmb_command_createdevice *command;
+ struct dxgkvmb_command_createdevice_return result = { };
+ struct dxgvmbusmsg msg;
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_CREATEDEVICE,
+ process->host_handle);
+ command->flags = args->flags;
+ command->error_code = &dxgglobal->device_state_counter;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0)
+ result.device.v = 0;
+ free_message(&msg, process);
+cleanup:
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return result.device;
+}
+
+int dxgvmb_send_destroy_device(struct dxgadapter *adapter,
+ struct dxgprocess *process,
+ struct d3dkmthandle h)
+{
+ int ret;
+ struct dxgkvmb_command_destroydevice *command;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_DESTROYDEVICE,
+ process->host_handle);
+ command->device = h;
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+struct d3dkmthandle
+dxgvmb_send_create_context(struct dxgadapter *adapter,
+ struct dxgprocess *process,
+ struct d3dkmt_createcontextvirtual *args)
+{
+ struct dxgkvmb_command_createcontextvirtual *command = NULL;
+ u32 cmd_size;
+ int ret;
+ struct d3dkmthandle context = {};
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ if (args->priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ pr_err("PrivateDriverDataSize is invalid");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ cmd_size = sizeof(struct dxgkvmb_command_createcontextvirtual) +
+ args->priv_drv_data_size - 1;
+
+ 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_CREATECONTEXTVIRTUAL,
+ process->host_handle);
+ command->device = args->device;
+ command->node_ordinal = args->node_ordinal;
+ command->engine_affinity = args->engine_affinity;
+ command->flags = args->flags;
+ command->client_hint = args->client_hint;
+ command->priv_drv_data_size = args->priv_drv_data_size;
+ if (args->priv_drv_data_size) {
+ ret = copy_from_user(command->priv_drv_data,
+ args->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s Faled to copy private data",
+ __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+ /* Input command is returned back as output */
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ command, cmd_size);
+ if (ret < 0) {
+ goto cleanup;
+ } else {
+ context = command->context;
+ if (args->priv_drv_data_size) {
+ ret = copy_to_user(args->priv_drv_data,
+ command->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s Faled to copy private data to user",
+ __func__);
+ ret = -EINVAL;
+ dxgvmb_send_destroy_context(adapter, process,
+ context);
+ context.v = 0;
+ }
+ }
+ }
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return context;
+}
+
+int dxgvmb_send_destroy_context(struct dxgadapter *adapter,
+ struct dxgprocess *process,
+ struct d3dkmthandle h)
+{
+ int ret;
+ struct dxgkvmb_command_destroycontext *command;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_DESTROYCONTEXT,
+ process->host_handle);
+ command->context = h;
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_queryadapterinfo *args)
+{
+ struct dxgkvmb_command_queryadapterinfo *command;
+ u32 cmd_size = sizeof(*command) + args->private_data_size - 1;
+ int ret;
+ u32 private_data_size;
+ void *private_data;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, cmd_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ ret = copy_from_user(command->private_data,
+ args->private_data, args->private_data_size);
+ if (ret) {
+ pr_err("%s Faled to copy private data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_QUERYADAPTERINFO,
+ process->host_handle);
+ command->private_data_size = args->private_data_size;
+ command->query_type = args->type;
+
+ if (dxgglobal->vmbus_ver >= DXGK_VMBUS_INTERFACE_VERSION) {
+ private_data = msg.msg;
+ private_data_size = command->private_data_size +
+ sizeof(struct ntstatus);
+ } else {
+ private_data = command->private_data;
+ private_data_size = command->private_data_size;
+ }
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ private_data, private_data_size);
+ if (ret < 0)
+ goto cleanup;
+
+ if (dxgglobal->vmbus_ver >= DXGK_VMBUS_INTERFACE_VERSION) {
+ ret = ntstatus2int(*(struct ntstatus *)private_data);
+ if (ret < 0)
+ goto cleanup;
+ private_data = (char *)private_data + sizeof(struct ntstatus);
+ }
+
+ switch (args->type) {
+ case _KMTQAITYPE_ADAPTERTYPE:
+ case _KMTQAITYPE_ADAPTERTYPE_RENDER:
+ {
+ struct d3dkmt_adaptertype *adapter_type =
+ (void *)private_data;
+ adapter_type->paravirtualized = 1;
+ adapter_type->display_supported = 0;
+ adapter_type->post_device = 0;
+ adapter_type->indirect_display_device = 0;
+ adapter_type->acg_supported = 0;
+ adapter_type->support_set_timings_from_vidpn = 0;
+ break;
+ }
+ default:
+ break;
+ }
+ ret = copy_to_user(args->private_data, private_data,
+ args->private_data_size);
+ if (ret) {
+ pr_err("%s Faled to copy private data to user", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
diff --git a/drivers/hv/dxgkrnl/hmgr.c b/drivers/hv/dxgkrnl/hmgr.c
index cdb6539df006..46a8e59b51b7 100644
--- a/drivers/hv/dxgkrnl/hmgr.c
+++ b/drivers/hv/dxgkrnl/hmgr.c
@@ -65,7 +65,220 @@ struct hmgrentry {
u32 destroyed:1;
};
+#define HMGRTABLE_SIZE_INCREMENT 1024
+#define HMGRTABLE_MIN_FREE_ENTRIES 128
#define HMGRTABLE_INVALID_INDEX (~((1 << HMGRHANDLE_INDEX_BITS) - 1))
+#define HMGRTABLE_SIZE_MAX 0xFFFFFFF
+
+static u32 table_size_increment = HMGRTABLE_SIZE_INCREMENT;
+
+static inline u32 get_unique(struct d3dkmthandle h)
+{
+ return (h.v & HMGRHANDLE_UNIQUE_MASK) >> HMGRHANDLE_UNIQUE_SHIFT;
+}
+
+static u32 get_index(struct d3dkmthandle h)
+{
+ return (h.v & HMGRHANDLE_INDEX_MASK) >> HMGRHANDLE_INDEX_SHIFT;
+}
+
+u32 get_instance(struct d3dkmthandle h)
+{
+ return (h.v & HMGRHANDLE_INSTANCE_MASK) >> HMGRHANDLE_INSTANCE_SHIFT;
+}
+
+static bool is_handle_valid(struct hmgrtable *table, struct d3dkmthandle h,
+ bool ignore_destroyed, enum hmgrentry_type t)
+{
+ u32 index = get_index(h);
+ u32 unique = get_unique(h);
+ struct hmgrentry *entry;
+
+ if (index >= table->table_size) {
+ pr_err("%s Invalid index %x %d\n", __func__, h.v, index);
+ return false;
+ }
+
+ entry = &table->entry_table[index];
+ if (unique != entry->unique) {
+ pr_err("%s Invalid unique %x %d %d %d %p",
+ __func__, h.v, unique, entry->unique,
+ index, entry->object);
+ return false;
+ }
+
+ if (entry->destroyed && !ignore_destroyed) {
+ pr_err("%s Invalid destroyed", __func__);
+ return false;
+ }
+
+ if (entry->type == HMGRENTRY_TYPE_FREE) {
+ pr_err("%s Entry is freed %x %d", __func__, h.v, index);
+ return false;
+ }
+
+ if (t != HMGRENTRY_TYPE_FREE && t != entry->type) {
+ pr_err("%s type mismatch %x %d %d", __func__, h.v,
+ t, entry->type);
+ return false;
+ }
+
+ return true;
+}
+
+static struct d3dkmthandle build_handle(u32 index, u32 unique, u32 instance)
+{
+ struct d3dkmthandle handle;
+
+ handle.v = (index << HMGRHANDLE_INDEX_SHIFT) & HMGRHANDLE_INDEX_MASK;
+ handle.v |= (unique << HMGRHANDLE_UNIQUE_SHIFT) &
+ HMGRHANDLE_UNIQUE_MASK;
+ handle.v |= (instance << HMGRHANDLE_INSTANCE_SHIFT) &
+ HMGRHANDLE_INSTANCE_MASK;
+
+ return handle;
+}
+
+inline u32 hmgrtable_get_used_entry_count(struct hmgrtable *table)
+{
+ DXGKRNL_ASSERT(table->table_size >= table->free_count);
+ return (table->table_size - table->free_count);
+}
+
+bool hmgrtable_mark_destroyed(struct hmgrtable *table, struct d3dkmthandle h)
+{
+ if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE))
+ return false;
+
+ table->entry_table[get_index(h)].destroyed = true;
+ return true;
+}
+
+bool hmgrtable_unmark_destroyed(struct hmgrtable *table, struct d3dkmthandle h)
+{
+ if (!is_handle_valid(table, h, true, HMGRENTRY_TYPE_FREE))
+ return true;
+
+ DXGKRNL_ASSERT(table->entry_table[get_index(h)].destroyed);
+ table->entry_table[get_index(h)].destroyed = 0;
+ return true;
+}
+
+static inline bool is_empty(struct hmgrtable *table)
+{
+ return (table->free_count == table->table_size);
+}
+
+void print_status(struct hmgrtable *table)
+{
+ int i;
+
+ dev_dbg(dxgglobaldev, "hmgrtable head, tail %p %d %d\n",
+ table, table->free_handle_list_head,
+ table->free_handle_list_tail);
+ if (table->entry_table == NULL)
+ return;
+ for (i = 0; i < 3; i++) {
+ if (table->entry_table[i].type != HMGRENTRY_TYPE_FREE)
+ dev_dbg(dxgglobaldev, "hmgrtable entry %p %d %p\n",
+ table, i, table->entry_table[i].object);
+ else
+ dev_dbg(dxgglobaldev, "hmgrtable entry %p %d %d %d\n",
+ table, i,
+ table->entry_table[i].next_free_index,
+ table->entry_table[i].prev_free_index);
+ }
+}
+
+static bool expand_table(struct hmgrtable *table, u32 NumEntries)
+{
+ u32 new_table_size;
+ struct hmgrentry *new_entry;
+ u32 table_index;
+ u32 new_free_count;
+ u32 prev_free_index;
+ u32 tail_index = table->free_handle_list_tail;
+
+ /* The tail should point to the last free element in the list */
+ if (table->free_count != 0) {
+ if (tail_index >= table->table_size ||
+ table->entry_table[tail_index].next_free_index !=
+ HMGRTABLE_INVALID_INDEX) {
+ pr_err("%s:corruption\n", __func__);
+ pr_err("tail_index: %x", tail_index);
+ pr_err("table size: %x", table->table_size);
+ pr_err("free_count: %d", table->free_count);
+ pr_err("NumEntries: %x", NumEntries);
+ return false;
+ }
+ }
+
+ new_free_count = table_size_increment + table->free_count;
+ new_table_size = table->table_size + table_size_increment;
+ if (new_table_size < NumEntries) {
+ new_free_count += NumEntries - new_table_size;
+ new_table_size = NumEntries;
+ }
+
+ if (new_table_size > HMGRHANDLE_INDEX_MAX) {
+ pr_err("%s:corruption\n", __func__);
+ return false;
+ }
+
+ new_entry = (struct hmgrentry *)
+ vzalloc(new_table_size * sizeof(struct hmgrentry));
+ if (new_entry == NULL) {
+ pr_err("%s:allocation failed\n", __func__);
+ return false;
+ }
+
+ if (table->entry_table) {
+ memcpy(new_entry, table->entry_table,
+ table->table_size * sizeof(struct hmgrentry));
+ vfree(table->entry_table);
+ } else {
+ table->free_handle_list_head = 0;
+ }
+
+ table->entry_table = new_entry;
+
+ /* Initialize new table entries and add to the free list */
+ table_index = table->table_size;
+
+ prev_free_index = table->free_handle_list_tail;
+
+ while (table_index < new_table_size) {
+ struct hmgrentry *entry = &table->entry_table[table_index];
+
+ entry->prev_free_index = prev_free_index;
+ entry->next_free_index = table_index + 1;
+ entry->type = HMGRENTRY_TYPE_FREE;
+ entry->unique = 1;
+ entry->instance = 0;
+ prev_free_index = table_index;
+
+ table_index++;
+ }
+
+ table->entry_table[table_index - 1].next_free_index =
+ (u32) HMGRTABLE_INVALID_INDEX;
+
+ if (table->free_count != 0) {
+ /* Link the current free list with the new entries */
+ struct hmgrentry *entry;
+
+ entry = &table->entry_table[table->free_handle_list_tail];
+ entry->next_free_index = table->table_size;
+ }
+ table->free_handle_list_tail = new_table_size - 1;
+ if (table->free_handle_list_head == HMGRTABLE_INVALID_INDEX)
+ table->free_handle_list_head = table->table_size;
+
+ table->table_size = new_table_size;
+ table->free_count = new_free_count;
+
+ return true;
+}
void hmgrtable_init(struct hmgrtable *table, struct dxgprocess *process)
{
@@ -86,3 +299,299 @@ void hmgrtable_destroy(struct hmgrtable *table)
}
}
+void hmgrtable_lock(struct hmgrtable *table, enum dxglockstate state)
+{
+ if (state == DXGLOCK_EXCL)
+ down_write(&table->table_lock);
+ else
+ down_read(&table->table_lock);
+}
+
+void hmgrtable_unlock(struct hmgrtable *table, enum dxglockstate state)
+{
+ if (state == DXGLOCK_EXCL)
+ up_write(&table->table_lock);
+ else
+ up_read(&table->table_lock);
+}
+
+struct d3dkmthandle hmgrtable_alloc_handle(struct hmgrtable *table,
+ void *object,
+ enum hmgrentry_type type,
+ bool make_valid)
+{
+ u32 index;
+ struct hmgrentry *entry;
+ u32 unique;
+
+ DXGKRNL_ASSERT(type <= HMGRENTRY_TYPE_LIMIT);
+ DXGKRNL_ASSERT(type > HMGRENTRY_TYPE_FREE);
+
+ if (table->free_count <= HMGRTABLE_MIN_FREE_ENTRIES) {
+ if (!expand_table(table, 0)) {
+ pr_err("hmgrtable expand_table failed\n");
+ return zerohandle;
+ }
+ }
+
+ if (table->free_handle_list_head >= table->table_size) {
+ pr_err("hmgrtable corrupted handle table head\n");
+ return zerohandle;
+ }
+
+ index = table->free_handle_list_head;
+ entry = &table->entry_table[index];
+
+ if (entry->type != HMGRENTRY_TYPE_FREE) {
+ pr_err("hmgrtable expected free handle\n");
+ return zerohandle;
+ }
+
+ table->free_handle_list_head = entry->next_free_index;
+
+ if (entry->next_free_index != table->free_handle_list_tail) {
+ if (entry->next_free_index >= table->table_size) {
+ pr_err("hmgrtable invalid next free index\n");
+ return zerohandle;
+ }
+ table->entry_table[entry->next_free_index].prev_free_index =
+ HMGRTABLE_INVALID_INDEX;
+ }
+
+ unique = table->entry_table[index].unique;
+
+ table->entry_table[index].object = object;
+ table->entry_table[index].type = type;
+ table->entry_table[index].instance = 0;
+ table->entry_table[index].destroyed = !make_valid;
+ table->free_count--;
+ DXGKRNL_ASSERT(table->free_count <= table->table_size);
+
+ return build_handle(index, unique, table->entry_table[index].instance);
+}
+
+int hmgrtable_assign_handle_safe(struct hmgrtable *table,
+ void *object,
+ enum hmgrentry_type type,
+ struct d3dkmthandle h)
+{
+ int ret;
+
+ hmgrtable_lock(table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(table, object, type, h);
+ hmgrtable_unlock(table, DXGLOCK_EXCL);
+ return ret;
+}
+
+int hmgrtable_assign_handle(struct hmgrtable *table, void *object,
+ enum hmgrentry_type type, struct d3dkmthandle h)
+{
+ u32 index = get_index(h);
+ u32 unique = get_unique(h);
+ struct hmgrentry *entry = NULL;
+
+ dev_dbg(dxgglobaldev, "%s %x, %d %p, %p\n",
+ __func__, h.v, index, object, table);
+
+ if (index >= HMGRHANDLE_INDEX_MAX) {
+ pr_err("handle index is too big: %x %d", h.v, index);
+ return -EINVAL;
+ }
+
+ if (index >= table->table_size) {
+ u32 new_size = index + table_size_increment;
+
+ if (new_size > HMGRHANDLE_INDEX_MAX)
+ new_size = HMGRHANDLE_INDEX_MAX;
+ if (!expand_table(table, new_size)) {
+ pr_err("failed to expand handle table %d", new_size);
+ return -ENOMEM;
+ }
+ }
+
+ entry = &table->entry_table[index];
+
+ if (entry->type != HMGRENTRY_TYPE_FREE) {
+ pr_err("the entry is already busy: %d %x",
+ entry->type,
+ hmgrtable_build_entry_handle(table, index).v);
+ return -EINVAL;
+ }
+
+ if (index != table->free_handle_list_tail) {
+ if (entry->next_free_index >= table->table_size) {
+ pr_err("hmgr: invalid next free index %d\n",
+ entry->next_free_index);
+ return -EINVAL;
+ }
+ table->entry_table[entry->next_free_index].prev_free_index =
+ entry->prev_free_index;
+ } else {
+ table->free_handle_list_tail = entry->prev_free_index;
+ }
+
+ if (index != table->free_handle_list_head) {
+ if (entry->prev_free_index >= table->table_size) {
+ pr_err("hmgr: invalid next prev index %d\n",
+ entry->prev_free_index);
+ return -EINVAL;
+ }
+ table->entry_table[entry->prev_free_index].next_free_index =
+ entry->next_free_index;
+ } else {
+ table->free_handle_list_head = entry->next_free_index;
+ }
+
+ entry->prev_free_index = HMGRTABLE_INVALID_INDEX;
+ entry->next_free_index = HMGRTABLE_INVALID_INDEX;
+ entry->object = object;
+ entry->type = type;
+ entry->instance = 0;
+ entry->unique = unique;
+ entry->destroyed = false;
+
+ table->free_count--;
+ DXGKRNL_ASSERT(table->free_count <= table->table_size);
+ return 0;
+}
+
+struct d3dkmthandle hmgrtable_alloc_handle_safe(struct hmgrtable *table,
+ void *obj,
+ enum hmgrentry_type type,
+ bool make_valid)
+{
+ struct d3dkmthandle h;
+
+ hmgrtable_lock(table, DXGLOCK_EXCL);
+ h = hmgrtable_alloc_handle(table, obj, type, make_valid);
+ hmgrtable_unlock(table, DXGLOCK_EXCL);
+ return h;
+}
+
+void hmgrtable_free_handle(struct hmgrtable *table, enum hmgrentry_type t,
+ struct d3dkmthandle h)
+{
+ struct hmgrentry *entry;
+ u32 i = get_index(h);
+
+ dev_dbg(dxgglobaldev, "%s: %p %x\n", __func__, table, h.v);
+
+ /* Ignore the destroyed flag when checking the handle */
+ if (is_handle_valid(table, h, true, t)) {
+ DXGKRNL_ASSERT(table->free_count < table->table_size);
+ entry = &table->entry_table[i];
+ entry->unique = 1;
+ entry->type = HMGRENTRY_TYPE_FREE;
+ entry->destroyed = 0;
+ if (entry->unique != HMGRHANDLE_UNIQUE_MAX)
+ entry->unique += 1;
+ else
+ entry->unique = 1;
+
+ table->free_count++;
+ DXGKRNL_ASSERT(table->free_count <= table->table_size);
+
+ /*
+ * Insert the index to the free list at the tail.
+ */
+ entry->next_free_index = HMGRTABLE_INVALID_INDEX;
+ entry->prev_free_index = table->free_handle_list_tail;
+ entry = &table->entry_table[table->free_handle_list_tail];
+ entry->next_free_index = i;
+ table->free_handle_list_tail = i;
+ } else {
+ pr_err("%s:error: %d %x\n", __func__, i, h.v);
+ }
+}
+
+void hmgrtable_free_handle_safe(struct hmgrtable *table, enum hmgrentry_type t,
+ struct d3dkmthandle h)
+{
+ hmgrtable_lock(table, DXGLOCK_EXCL);
+ hmgrtable_free_handle(table, t, h);
+ hmgrtable_unlock(table, DXGLOCK_EXCL);
+}
+
+struct d3dkmthandle hmgrtable_build_entry_handle(struct hmgrtable *table,
+ u32 index)
+{
+ DXGKRNL_ASSERT(index < table->table_size);
+
+ return build_handle(index, table->entry_table[index].unique,
+ table->entry_table[index].instance);
+}
+
+void *hmgrtable_get_object(struct hmgrtable *table, struct d3dkmthandle h)
+{
+ if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE))
+ return NULL;
+
+ return table->entry_table[get_index(h)].object;
+}
+
+void *hmgrtable_get_object_by_type(struct hmgrtable *table,
+ enum hmgrentry_type type,
+ struct d3dkmthandle h)
+{
+ if (!is_handle_valid(table, h, false, type)) {
+ pr_err("%s invalid handle %x\n", __func__, h.v);
+ return NULL;
+ }
+ return table->entry_table[get_index(h)].object;
+}
+
+void *hmgrtable_get_entry_object(struct hmgrtable *table, u32 index)
+{
+ DXGKRNL_ASSERT(index < table->table_size);
+ DXGKRNL_ASSERT(table->entry_table[index].type != HMGRENTRY_TYPE_FREE);
+
+ return table->entry_table[index].object;
+}
+
+enum hmgrentry_type hmgrtable_get_entry_type(struct hmgrtable *table,
+ u32 index)
+{
+ DXGKRNL_ASSERT(index < table->table_size);
+ return (enum hmgrentry_type)table->entry_table[index].type;
+}
+
+enum hmgrentry_type hmgrtable_get_object_type(struct hmgrtable *table,
+ struct d3dkmthandle h)
+{
+ if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE))
+ return HMGRENTRY_TYPE_FREE;
+
+ return hmgrtable_get_entry_type(table, get_index(h));
+}
+
+void *hmgrtable_get_object_ignore_destroyed(struct hmgrtable *table,
+ struct d3dkmthandle h,
+ enum hmgrentry_type type)
+{
+ if (!is_handle_valid(table, h, true, type))
+ return NULL;
+ return table->entry_table[get_index(h)].object;
+}
+
+bool hmgrtable_next_entry(struct hmgrtable *tbl,
+ u32 *index,
+ enum hmgrentry_type *type,
+ struct d3dkmthandle *handle,
+ void **object)
+{
+ u32 i;
+ struct hmgrentry *entry;
+
+ for (i = *index; i < tbl->table_size; i++) {
+ entry = &tbl->entry_table[i];
+ if (entry->type != HMGRENTRY_TYPE_FREE) {
+ *index = i + 1;
+ *object = entry->object;
+ *handle = build_handle(i, entry->unique,
+ entry->instance);
+ *type = entry->type;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index c6548fbdd8ef..590ce9bfa592 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -17,21 +17,825 @@
#include <linux/anon_inodes.h>
#include <linux/mman.h>
+#include "dxgkrnl.h"
+#include "dxgvmbus.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "dxgk:err: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
+
+struct ioctl_desc {
+ int (*ioctl_callback)(struct dxgprocess *p, void __user *arg);
+ u32 ioctl;
+ u32 arg_size;
+};
+static struct ioctl_desc ioctls[LX_IO_MAX + 1];
+
+static char *errorstr(int ret)
+{
+ return ret < 0 ? "err" : "";
+}
+
+static int dxgk_open_adapter_from_luid(struct dxgprocess *process,
+ void *__user inargs)
+{
+ struct d3dkmt_openadapterfromluid args;
+ int ret;
+ struct dxgadapter *entry;
+ struct dxgadapter *adapter = NULL;
+ struct d3dkmt_openadapterfromluid *__user result = inargs;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s Faled to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED);
+ dxgglobal_acquire_process_adapter_lock();
+
+ list_for_each_entry(entry, &dxgglobal->adapter_list_head,
+ adapter_list_entry) {
+ if (dxgadapter_acquire_lock_shared(entry) == 0) {
+ dev_dbg(dxgglobaldev, "Compare luids: %d:%d %d:%d",
+ entry->luid.b, entry->luid.a,
+ args.adapter_luid.b, args.adapter_luid.a);
+ if (*(u64 *) &entry->luid ==
+ *(u64 *) &args.adapter_luid) {
+ ret =
+ dxgprocess_open_adapter(process, entry,
+ &args.adapter_handle);
+
+ if (ret >= 0) {
+ ret = copy_to_user(
+ &result->adapter_handle,
+ &args.adapter_handle,
+ sizeof(struct d3dkmthandle));
+ if (ret)
+ ret = -EINVAL;
+ }
+ adapter = entry;
+ }
+ dxgadapter_release_lock_shared(entry);
+ if (adapter)
+ break;
+ }
+ }
+
+ dxgglobal_release_process_adapter_lock();
+ dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED);
+
+ if (args.adapter_handle.v == 0)
+ ret = -EINVAL;
+
+cleanup:
+
+ if (ret < 0)
+ dxgprocess_close_adapter(process, args.adapter_handle);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgkp_enum_adapters(struct dxgprocess *process,
+ union d3dkmt_enumadapters_filter filter,
+ u32 adapter_count_max,
+ struct d3dkmt_adapterinfo *__user info_out,
+ u32 * __user adapter_count_out)
+{
+ int ret = 0;
+ struct dxgadapter *entry;
+ struct d3dkmt_adapterinfo *info = NULL;
+ struct dxgadapter **adapters = NULL;
+ int adapter_count = 0;
+ int i;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ if (info_out == NULL || adapter_count_max == 0) {
+ dev_dbg(dxgglobaldev, "buffer is NULL");
+ ret = copy_to_user(adapter_count_out,
+ &dxgglobal->num_adapters, sizeof(u32));
+ if (ret) {
+ pr_err("%s copy_to_user faled", __func__);
+ ret = -EINVAL;
+ }
+ goto cleanup;
+ }
+
+ if (adapter_count_max > 0xFFFF) {
+ pr_err("too many adapters");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ info = vzalloc(sizeof(struct d3dkmt_adapterinfo) * adapter_count_max);
+ if (info == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ adapters = vzalloc(sizeof(struct dxgadapter *) * adapter_count_max);
+ if (adapters == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED);
+ dxgglobal_acquire_process_adapter_lock();
+
+ list_for_each_entry(entry, &dxgglobal->adapter_list_head,
+ adapter_list_entry) {
+ if (dxgadapter_acquire_lock_shared(entry) == 0) {
+ struct d3dkmt_adapterinfo *inf = &info[adapter_count];
+
+ ret = dxgprocess_open_adapter(process, entry,
+ &inf->adapter_handle);
+ if (ret >= 0) {
+ inf->adapter_luid = entry->luid;
+ adapters[adapter_count] = entry;
+ dev_dbg(dxgglobaldev, "adapter: %x %x:%x",
+ inf->adapter_handle.v,
+ inf->adapter_luid.b,
+ inf->adapter_luid.a);
+ adapter_count++;
+ }
+ dxgadapter_release_lock_shared(entry);
+ }
+ if (ret < 0)
+ break;
+ }
+
+ dxgglobal_release_process_adapter_lock();
+ dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED);
+
+ if (adapter_count > adapter_count_max) {
+ ret = STATUS_BUFFER_TOO_SMALL;
+ dev_dbg(dxgglobaldev, "Too many adapters");
+ ret = copy_to_user(adapter_count_out,
+ &dxgglobal->num_adapters, sizeof(u32));
+ if (ret) {
+ pr_err("%s copy_to_user failed", __func__);
+ ret = -EINVAL;
+ }
+ goto cleanup;
+ }
+
+ ret = copy_to_user(adapter_count_out, &adapter_count,
+ sizeof(adapter_count));
+ if (ret) {
+ pr_err("%s failed to copy adapter_count", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_to_user(info_out, info, sizeof(info[0]) * adapter_count);
+ if (ret) {
+ pr_err("%s failed to copy adapter info", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (ret >= 0) {
+ dev_dbg(dxgglobaldev, "found %d adapters", adapter_count);
+ goto success;
+ }
+ if (info) {
+ for (i = 0; i < adapter_count; i++)
+ dxgprocess_close_adapter(process,
+ info[i].adapter_handle);
+ }
+success:
+ if (info)
+ vfree(info);
+ if (adapters)
+ vfree(adapters);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_enum_adapters(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_enumadapters2 args;
+ int ret;
+ struct dxgadapter *entry;
+ struct d3dkmt_adapterinfo *info = NULL;
+ struct dxgadapter **adapters = NULL;
+ int adapter_count = 0;
+ int i;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.adapters == NULL) {
+ dev_dbg(dxgglobaldev, "buffer is NULL");
+ args.num_adapters = dxgglobal->num_adapters;
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy args to user", __func__);
+ ret = -EINVAL;
+ }
+ goto cleanup;
+ }
+ if (args.num_adapters < dxgglobal->num_adapters) {
+ args.num_adapters = dxgglobal->num_adapters;
+ dev_dbg(dxgglobaldev, "buffer is too small");
+ ret = -EOVERFLOW;
+ goto cleanup;
+ }
+
+ if (args.num_adapters > D3DKMT_ADAPTERS_MAX) {
+ dev_dbg(dxgglobaldev, "too many adapters");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ info = vzalloc(sizeof(struct d3dkmt_adapterinfo) * args.num_adapters);
+ if (info == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ adapters = vzalloc(sizeof(struct dxgadapter *) * args.num_adapters);
+ if (adapters == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED);
+ dxgglobal_acquire_process_adapter_lock();
+
+ list_for_each_entry(entry, &dxgglobal->adapter_list_head,
+ adapter_list_entry) {
+ if (dxgadapter_acquire_lock_shared(entry) == 0) {
+ struct d3dkmt_adapterinfo *inf = &info[adapter_count];
+
+ ret = dxgprocess_open_adapter(process, entry,
+ &inf->adapter_handle);
+ if (ret >= 0) {
+ inf->adapter_luid = entry->luid;
+ adapters[adapter_count] = entry;
+ dev_dbg(dxgglobaldev, "adapter: %x %llx",
+ inf->adapter_handle.v,
+ *(u64 *) &inf->adapter_luid);
+ adapter_count++;
+ }
+ dxgadapter_release_lock_shared(entry);
+ }
+ if (ret < 0)
+ break;
+ }
+
+ dxgglobal_release_process_adapter_lock();
+ dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED);
+
+ args.num_adapters = adapter_count;
+
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy args to user", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_to_user(args.adapters, info,
+ sizeof(info[0]) * args.num_adapters);
+ if (ret) {
+ pr_err("%s failed to copy adapter info to user", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (ret < 0) {
+ if (info) {
+ for (i = 0; i < args.num_adapters; i++) {
+ dxgprocess_close_adapter(process,
+ info[i].adapter_handle);
+ }
+ }
+ } else {
+ dev_dbg(dxgglobaldev, "found %d adapters", args.num_adapters);
+ }
+
+ if (info)
+ vfree(info);
+ if (adapters)
+ vfree(adapters);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_enum_adapters3(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_enumadapters3 args;
+ int ret;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgkp_enum_adapters(process, args.filter,
+ args.adapter_count,
+ args.adapters,
+ &((struct d3dkmt_enumadapters3 *)inargs)->
+ adapter_count);
+
+cleanup:
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_close_adapter(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmthandle args;
+ int ret;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgprocess_close_adapter(process, args);
+ if (ret < 0)
+ pr_err("%s failed", __func__);
+
+cleanup:
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_query_adapter_info(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_queryadapterinfo args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.private_data_size > DXG_MAX_VM_BUS_PACKET_SIZE ||
+ args.private_data_size == 0) {
+ pr_err("invalid private data size");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dev_dbg(dxgglobaldev, "Type: %d Size: %x",
+ args.type, args.private_data_size);
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = dxgvmb_send_query_adapter_info(process, adapter, &args);
+
+ dxgadapter_release_lock_shared(adapter);
+
+cleanup:
+
+ if (adapter)
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_create_device(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_createdevice args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ struct d3dkmthandle host_device_handle = {};
+ bool adapter_locked = false;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /* The call acquires reference on the adapter */
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgdevice_create(adapter, process);
+ if (device == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0)
+ goto cleanup;
+
+ adapter_locked = true;
+
+ host_device_handle = dxgvmb_send_create_device(adapter, process, &args);
+ if (host_device_handle.v) {
+ ret = copy_to_user(&((struct d3dkmt_createdevice *)inargs)->
+ device, &host_device_handle,
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy device handle", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(&process->handle_table, device,
+ HMGRENTRY_TYPE_DXGDEVICE,
+ host_device_handle);
+ if (ret >= 0) {
+ device->handle = host_device_handle;
+ device->handle_valid = 1;
+ device->object_state = DXGOBJECTSTATE_ACTIVE;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+ }
+
+cleanup:
+
+ if (ret < 0) {
+ if (host_device_handle.v)
+ dxgvmb_send_destroy_device(adapter, process,
+ host_device_handle);
+ if (device)
+ dxgdevice_destroy(device);
+ }
+
+ if (adapter_locked)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (adapter)
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_destroy_device(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_destroydevice args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ device = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGDEVICE,
+ args.device);
+ if (device) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGDEVICE, args.device);
+ device->handle_valid = 0;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (device == NULL) {
+ pr_err("invalid device handle: %x", args.device.v);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+
+ dxgdevice_destroy(device);
+
+ if (dxgadapter_acquire_lock_shared(adapter) == 0) {
+ dxgvmb_send_destroy_device(adapter, process, args.device);
+ dxgadapter_release_lock_shared(adapter);
+ }
+
+cleanup:
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_create_context_virtual(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_createcontextvirtual args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxgcontext *context = NULL;
+ struct d3dkmthandle host_context_handle = {};
+ bool device_lock_acquired = false;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0)
+ goto cleanup;
+
+ device_lock_acquired = true;
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ context = dxgcontext_create(device);
+ if (context == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ host_context_handle = dxgvmb_send_create_context(adapter,
+ process, &args);
+ if (host_context_handle.v) {
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(&process->handle_table, context,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ host_context_handle);
+ if (ret >= 0)
+ context->handle = host_context_handle;
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+ if (ret < 0)
+ goto cleanup;
+ ret = copy_to_user(&((struct d3dkmt_createcontextvirtual *)
+ inargs)->context, &host_context_handle,
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy context handle", __func__);
+ ret = -EINVAL;
+ }
+ } else {
+ pr_err("invalid host handle");
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (ret < 0) {
+ if (host_context_handle.v) {
+ dxgvmb_send_destroy_context(adapter, process,
+ host_context_handle);
+ }
+ if (context)
+ dxgcontext_destroy_safe(process, context);
+ }
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device) {
+ if (device_lock_acquired)
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_destroy_context(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_destroycontext args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgcontext *context = NULL;
+ struct dxgdevice *device = NULL;
+ struct d3dkmthandle device_handle = {};
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ context = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ args.context);
+ if (context) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGCONTEXT, args.context);
+ context->handle.v = 0;
+ device_handle = context->device_handle;
+ context->object_state = DXGOBJECTSTATE_DESTROYED;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (context == NULL) {
+ pr_err("invalid context handle: %x", args.context.v);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ 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_destroy_context(adapter, process, args.context);
+
+ dxgcontext_destroy_safe(process, context);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int dxgk_create_hwcontext(struct dxgprocess *process,
+ void *__user inargs)
+{
+ /* This is obsolete entry point */
+ return -ENOTTY;
+}
+
+static int dxgk_destroy_hwcontext(struct dxgprocess *process,
+ void *__user inargs)
+{
+ /* This is obsolete entry point */
+ return -ENOTTY;
+}
+
+static int
+dxgk_create_context(struct dxgprocess *process, void *__user inargs)
+{
+ pr_err("%s is not implemented", __func__);
+ return -ENOTTY;
+}
+
/*
- * Placeholder for IOCTL implementation
+ * IOCTL processing
+ * The driver IOCTLs return
+ * - 0 in case of success
+ * - positive values, which are Windows NTSTATUS (for example, STATUS_PENDING).
+ * Positive values are success codes.
+ * - Linux negative error codes
*/
+static int dxgk_ioctl(struct file *f, unsigned int p1, unsigned long p2)
+{
+ int code = _IOC_NR(p1);
+ int status;
+ struct dxgprocess *process;
+
+ if (code < 1 || code > LX_IO_MAX) {
+ pr_err("bad ioctl %x %x %x %x",
+ code, _IOC_TYPE(p1), _IOC_SIZE(p1), _IOC_DIR(p1));
+ return -ENOTTY;
+ }
+ if (ioctls[code].ioctl_callback == NULL) {
+ pr_err("ioctl callback is NULL %x", code);
+ return -ENOTTY;
+ }
+ if (ioctls[code].ioctl != p1) {
+ pr_err("ioctl mismatch. Code: %x User: %x Kernel: %x",
+ code, p1, ioctls[code].ioctl);
+ return -ENOTTY;
+ }
+ process = (struct dxgprocess *)f->private_data;
+ if (process->tgid != current->tgid) {
+ pr_err("Call from a wrong process: %d %d",
+ process->tgid, current->tgid);
+ return -ENOTTY;
+ }
+ status = ioctls[code].ioctl_callback(process, (void *__user)p2);
+ return status;
+}
long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2)
{
- return -ENODEV;
+ dev_dbg(dxgglobaldev, " compat ioctl %x", p1);
+ return dxgk_ioctl(f, p1, p2);
}
long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2)
{
- return -ENODEV;
+ dev_dbg(dxgglobaldev, " unlocked ioctl %x Code:%d", p1, _IOC_NR(p1));
+ return dxgk_ioctl(f, p1, p2);
}
+#define SET_IOCTL(callback, v) \
+ ioctls[_IOC_NR(v)].ioctl_callback = callback; \
+ ioctls[_IOC_NR(v)].ioctl = v
+
void init_ioctls(void)
{
- /* Placeholder */
+ SET_IOCTL(/*0x1 */ dxgk_open_adapter_from_luid,
+ LX_DXOPENADAPTERFROMLUID);
+ SET_IOCTL(/*0x2 */ dxgk_create_device,
+ LX_DXCREATEDEVICE);
+ SET_IOCTL(/*0x3 */ dxgk_create_context,
+ LX_DXCREATECONTEXT);
+ SET_IOCTL(/*0x4 */ dxgk_create_context_virtual,
+ LX_DXCREATECONTEXTVIRTUAL);
+ SET_IOCTL(/*0x5 */ dxgk_destroy_context,
+ LX_DXDESTROYCONTEXT);
+ SET_IOCTL(/*0x9 */ dxgk_query_adapter_info,
+ LX_DXQUERYADAPTERINFO);
+ SET_IOCTL(/*0x14 */ dxgk_enum_adapters,
+ LX_DXENUMADAPTERS2);
+ SET_IOCTL(/*0x15 */ dxgk_close_adapter,
+ LX_DXCLOSEADAPTER);
+ SET_IOCTL(/*0x17 */ dxgk_create_hwcontext,
+ LX_DXCREATEHWCONTEXT);
+ SET_IOCTL(/*0x19 */ dxgk_destroy_device,
+ LX_DXDESTROYDEVICE);
+ SET_IOCTL(/*0x1a */ dxgk_destroy_hwcontext,
+ LX_DXDESTROYHWCONTEXT);
+ SET_IOCTL(/*0x3e */ dxgk_enum_adapters3,
+ LX_DXENUMADAPTERS3);
}
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v1 2/9] drivers: hv: dxgkrnl: Open device object, adapter enumeration, dxgdevice, dxgcontext creation
2022-01-12 19:55 ` [PATCH v1 2/9] drivers: hv: dxgkrnl: Open device object, adapter enumeration, dxgdevice, dxgcontext creation Iouri Tarassov
@ 2022-01-13 7:41 ` Greg KH
2022-01-13 7:44 ` kernel test robot
1 sibling, 0 replies; 33+ messages in thread
From: Greg KH @ 2022-01-13 7:41 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On Wed, Jan 12, 2022 at 11:55:07AM -0800, Iouri Tarassov wrote:
> - Handle opening of the device (/dev/dxg) file object and creation of
> dxgprocess. dxgprocess is created for each process, which opens /dev/dxg.
> dxgprocess is ref counted, so the exicting dxgprocess objects is used for
> a process, which opens the device object multiple time.
> dxgprocess is destroyed when the device object is closed.
>
> - Implement ioctls for virtual GPU adapter enumeration:
> LX_DXENUMADAPTERS2, LX_DXENUMADAPTERS3
> The IOCTLs return a d3dkmt handle for each enumerated adapter.
>
> - Implement ioctl to query adapter information:
> LX_DXQUERYADAPTERINFO.
>
> - Implement ioctls to open and closet a dxgadapter object:
> LX_DXOPENADAPTERFROMLUID, LX_DXCLOSEADAPTER
> Note that dxgadapter is opened when LX_DXENUMADAPTERS2, LX_DXENUMADAPTERS3
> are called.
>
> - Implement ioctls for dxgdevice and dxgcontext creation/destruction:
> LX_DXCREATEDEVICE, LX_DXCREATECONTEXT, LX_DXCREATECONTEXTVIRTUAL,
> LX_DXDESTROYCONTEXT, LX_DXCREATEHWCONTEXT, LX_DXDESTROYDEVICE,
> LX_DXDESTROYHWCONTEXT
Hint, when you have to list all of the different things you are doing in
a single commit, that is a good clue that you should be splitting up the
commit into "one per thing".
This commit has way too many things happening all at once, and is very
difficult to review because of that. What would you do if you were
confronted with a single patch like this and you had to review it?
Make it trivial to review, please break this up into smaller pieces.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 2/9] drivers: hv: dxgkrnl: Open device object, adapter enumeration, dxgdevice, dxgcontext creation
2022-01-12 19:55 ` [PATCH v1 2/9] drivers: hv: dxgkrnl: Open device object, adapter enumeration, dxgdevice, dxgcontext creation Iouri Tarassov
2022-01-13 7:41 ` Greg KH
@ 2022-01-13 7:44 ` kernel test robot
1 sibling, 0 replies; 33+ messages in thread
From: kernel test robot @ 2022-01-13 7:44 UTC (permalink / raw)
To: Iouri Tarassov, kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: llvm, kbuild-all, linux-kernel, spronovo, gregkh
Hi Iouri,
I love your patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v5.16 next-20220113]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git e3084ed48fd6b661fe434da0cb36d7d6706cf27f
config: arm64-randconfig-r032-20220113 (https://download.01.org/0day-ci/archive/20220113/202201131549.w952i85x-lkp@intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project d1021978b8e7e35dcc30201ca1731d64b5a602a8)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm64 cross compiling tool for clang build
# apt-get install binutils-aarch64-linux-gnu
# https://github.com/0day-ci/linux/commit/91a8d0866d1c0efc52ca8e1cb504e0ec15c979e2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
git checkout 91a8d0866d1c0efc52ca8e1cb504e0ec15c979e2
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/hv/dxgkrnl/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> drivers/hv/dxgkrnl/hmgr.c:85:5: warning: no previous prototype for function 'get_instance' [-Wmissing-prototypes]
u32 get_instance(struct d3dkmthandle h)
^
drivers/hv/dxgkrnl/hmgr.c:85:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
u32 get_instance(struct d3dkmthandle h)
^
static
>> drivers/hv/dxgkrnl/hmgr.c:172:6: warning: no previous prototype for function 'print_status' [-Wmissing-prototypes]
void print_status(struct hmgrtable *table)
^
drivers/hv/dxgkrnl/hmgr.c:172:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void print_status(struct hmgrtable *table)
^
static
>> drivers/hv/dxgkrnl/hmgr.c:551:21: warning: no previous prototype for function 'hmgrtable_get_entry_type' [-Wmissing-prototypes]
enum hmgrentry_type hmgrtable_get_entry_type(struct hmgrtable *table,
^
drivers/hv/dxgkrnl/hmgr.c:551:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
enum hmgrentry_type hmgrtable_get_entry_type(struct hmgrtable *table,
^
static
drivers/hv/dxgkrnl/hmgr.c:167:20: warning: unused function 'is_empty' [-Wunused-function]
static inline bool is_empty(struct hmgrtable *table)
^
4 warnings generated.
--
>> drivers/hv/dxgkrnl/dxgadapter.c:261:6: warning: no previous prototype for function 'dxgdevice_mark_destroyed' [-Wmissing-prototypes]
void dxgdevice_mark_destroyed(struct dxgdevice *device)
^
drivers/hv/dxgkrnl/dxgadapter.c:261:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void dxgdevice_mark_destroyed(struct dxgdevice *device)
^
static
1 warning generated.
vim +/get_instance +85 drivers/hv/dxgkrnl/hmgr.c
84
> 85 u32 get_instance(struct d3dkmthandle h)
86 {
87 return (h.v & HMGRHANDLE_INSTANCE_MASK) >> HMGRHANDLE_INSTANCE_SHIFT;
88 }
89
90 static bool is_handle_valid(struct hmgrtable *table, struct d3dkmthandle h,
91 bool ignore_destroyed, enum hmgrentry_type t)
92 {
93 u32 index = get_index(h);
94 u32 unique = get_unique(h);
95 struct hmgrentry *entry;
96
97 if (index >= table->table_size) {
98 pr_err("%s Invalid index %x %d\n", __func__, h.v, index);
99 return false;
100 }
101
102 entry = &table->entry_table[index];
103 if (unique != entry->unique) {
104 pr_err("%s Invalid unique %x %d %d %d %p",
105 __func__, h.v, unique, entry->unique,
106 index, entry->object);
107 return false;
108 }
109
110 if (entry->destroyed && !ignore_destroyed) {
111 pr_err("%s Invalid destroyed", __func__);
112 return false;
113 }
114
115 if (entry->type == HMGRENTRY_TYPE_FREE) {
116 pr_err("%s Entry is freed %x %d", __func__, h.v, index);
117 return false;
118 }
119
120 if (t != HMGRENTRY_TYPE_FREE && t != entry->type) {
121 pr_err("%s type mismatch %x %d %d", __func__, h.v,
122 t, entry->type);
123 return false;
124 }
125
126 return true;
127 }
128
129 static struct d3dkmthandle build_handle(u32 index, u32 unique, u32 instance)
130 {
131 struct d3dkmthandle handle;
132
133 handle.v = (index << HMGRHANDLE_INDEX_SHIFT) & HMGRHANDLE_INDEX_MASK;
134 handle.v |= (unique << HMGRHANDLE_UNIQUE_SHIFT) &
135 HMGRHANDLE_UNIQUE_MASK;
136 handle.v |= (instance << HMGRHANDLE_INSTANCE_SHIFT) &
137 HMGRHANDLE_INSTANCE_MASK;
138
139 return handle;
140 }
141
142 inline u32 hmgrtable_get_used_entry_count(struct hmgrtable *table)
143 {
144 DXGKRNL_ASSERT(table->table_size >= table->free_count);
145 return (table->table_size - table->free_count);
146 }
147
148 bool hmgrtable_mark_destroyed(struct hmgrtable *table, struct d3dkmthandle h)
149 {
150 if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE))
151 return false;
152
153 table->entry_table[get_index(h)].destroyed = true;
154 return true;
155 }
156
157 bool hmgrtable_unmark_destroyed(struct hmgrtable *table, struct d3dkmthandle h)
158 {
159 if (!is_handle_valid(table, h, true, HMGRENTRY_TYPE_FREE))
160 return true;
161
162 DXGKRNL_ASSERT(table->entry_table[get_index(h)].destroyed);
163 table->entry_table[get_index(h)].destroyed = 0;
164 return true;
165 }
166
167 static inline bool is_empty(struct hmgrtable *table)
168 {
169 return (table->free_count == table->table_size);
170 }
171
> 172 void print_status(struct hmgrtable *table)
173 {
174 int i;
175
176 dev_dbg(dxgglobaldev, "hmgrtable head, tail %p %d %d\n",
177 table, table->free_handle_list_head,
178 table->free_handle_list_tail);
179 if (table->entry_table == NULL)
180 return;
181 for (i = 0; i < 3; i++) {
182 if (table->entry_table[i].type != HMGRENTRY_TYPE_FREE)
183 dev_dbg(dxgglobaldev, "hmgrtable entry %p %d %p\n",
184 table, i, table->entry_table[i].object);
185 else
186 dev_dbg(dxgglobaldev, "hmgrtable entry %p %d %d %d\n",
187 table, i,
188 table->entry_table[i].next_free_index,
189 table->entry_table[i].prev_free_index);
190 }
191 }
192
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v1 3/9] drivers: hv: dxgkrnl: Implement creation/destruction of GPU allocations/resources
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
2022-01-12 19:55 ` [PATCH v1 2/9] drivers: hv: dxgkrnl: Open device object, adapter enumeration, dxgdevice, dxgcontext creation Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-13 8:56 ` kernel test robot
2022-01-12 19:55 ` [PATCH v1 4/9] drivers: hv: dxgkrnl: Implement operations with GPU sync objects Iouri Tarassov
` (7 subsequent siblings)
9 siblings, 1 reply; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
Implemented the following ioctls:
- Creation and destruction of GPU accessible allocations:
LX_DXCREATEALLOCATION, LX_DXDESTROYALLOCATION2,
- LX_DXGETSHAREDRESOURCEADAPTERLUID
- LX_DXRENDER
At this moment GPU paravirtualization does not support D3DKMTRender API.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 310 ++++++++++++-
drivers/hv/dxgkrnl/dxgvmbus.c | 665 ++++++++++++++++++++++++++++
drivers/hv/dxgkrnl/ioctl.c | 745 ++++++++++++++++++++++++++++++++
3 files changed, 1705 insertions(+), 15 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index b461d6b6f55e..26648f7fe36f 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -447,6 +447,230 @@ void dxgdevice_remove_context(struct dxgdevice *device,
}
}
+void dxgdevice_add_alloc(struct dxgdevice *device, struct dxgallocation *alloc)
+{
+ dxgdevice_acquire_alloc_list_lock(device);
+ list_add_tail(&alloc->alloc_list_entry, &device->alloc_list_head);
+ kref_get(&device->device_kref);
+ alloc->owner.device = device;
+ dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_alloc(struct dxgdevice *device,
+ struct dxgallocation *alloc)
+{
+ if (alloc->alloc_list_entry.next) {
+ list_del(&alloc->alloc_list_entry);
+ alloc->alloc_list_entry.next = NULL;
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+}
+
+void dxgdevice_remove_alloc_safe(struct dxgdevice *device,
+ struct dxgallocation *alloc)
+{
+ dxgdevice_acquire_alloc_list_lock(device);
+ dxgdevice_remove_alloc(device, alloc);
+ dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_add_resource(struct dxgdevice *device, struct dxgresource *res)
+{
+ dxgdevice_acquire_alloc_list_lock(device);
+ list_add_tail(&res->resource_list_entry, &device->resource_list_head);
+ kref_get(&device->device_kref);
+ dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_resource(struct dxgdevice *device,
+ struct dxgresource *res)
+{
+ if (res->resource_list_entry.next) {
+ list_del(&res->resource_list_entry);
+ res->resource_list_entry.next = NULL;
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+}
+
+struct dxgsharedresource *dxgsharedresource_create(struct dxgadapter *adapter)
+{
+ struct dxgsharedresource *resource;
+
+ resource = vzalloc(sizeof(*resource));
+ if (resource) {
+ INIT_LIST_HEAD(&resource->resource_list_head);
+ kref_init(&resource->sresource_kref);
+ mutex_init(&resource->fd_mutex);
+ resource->adapter = adapter;
+ }
+ return resource;
+}
+
+void dxgsharedresource_destroy(struct kref *refcount)
+{
+ struct dxgsharedresource *resource;
+
+ resource = container_of(refcount, struct dxgsharedresource,
+ sresource_kref);
+ if (resource->runtime_private_data)
+ vfree(resource->runtime_private_data);
+ if (resource->resource_private_data)
+ vfree(resource->resource_private_data);
+ if (resource->alloc_private_data_sizes)
+ vfree(resource->alloc_private_data_sizes);
+ if (resource->alloc_private_data)
+ vfree(resource->alloc_private_data);
+ vfree(resource);
+}
+
+void dxgsharedresource_add_resource(struct dxgsharedresource *shared_resource,
+ struct dxgresource *resource)
+{
+ down_write(&shared_resource->adapter->shared_resource_list_lock);
+ dev_dbg(dxgglobaldev, "%s: %p %p", __func__, shared_resource, resource);
+ list_add_tail(&resource->shared_resource_list_entry,
+ &shared_resource->resource_list_head);
+ kref_get(&shared_resource->sresource_kref);
+ kref_get(&resource->resource_kref);
+ resource->shared_owner = shared_resource;
+ up_write(&shared_resource->adapter->shared_resource_list_lock);
+}
+
+void dxgsharedresource_remove_resource(struct dxgsharedresource
+ *shared_resource,
+ struct dxgresource *resource)
+{
+ struct dxgadapter *adapter = shared_resource->adapter;
+
+ down_write(&adapter->shared_resource_list_lock);
+ dev_dbg(dxgglobaldev, "%s: %p %p", __func__, shared_resource, resource);
+ if (resource->shared_resource_list_entry.next) {
+ list_del(&resource->shared_resource_list_entry);
+ resource->shared_resource_list_entry.next = NULL;
+ kref_put(&shared_resource->sresource_kref,
+ dxgsharedresource_destroy);
+ resource->shared_owner = NULL;
+ kref_put(&resource->resource_kref, dxgresource_release);
+ }
+ up_write(&adapter->shared_resource_list_lock);
+}
+
+struct dxgresource *dxgresource_create(struct dxgdevice *device)
+{
+ struct dxgresource *resource = vzalloc(sizeof(struct dxgresource));
+
+ if (resource) {
+ kref_init(&resource->resource_kref);
+ resource->device = device;
+ resource->process = device->process;
+ resource->object_state = DXGOBJECTSTATE_ACTIVE;
+ mutex_init(&resource->resource_mutex);
+ INIT_LIST_HEAD(&resource->alloc_list_head);
+ dxgdevice_add_resource(device, resource);
+ }
+ return resource;
+}
+
+void dxgresource_free_handle(struct dxgresource *resource)
+{
+ struct dxgallocation *alloc;
+ struct dxgprocess *process;
+
+ if (resource->handle_valid) {
+ process = resource->device->process;
+ hmgrtable_free_handle_safe(&process->handle_table,
+ HMGRENTRY_TYPE_DXGRESOURCE,
+ resource->handle);
+ resource->handle_valid = 0;
+ }
+ list_for_each_entry(alloc, &resource->alloc_list_head,
+ alloc_list_entry) {
+ dxgallocation_free_handle(alloc);
+ }
+}
+
+void dxgresource_destroy(struct dxgresource *resource)
+{
+ /* device->alloc_list_lock is held */
+ struct dxgallocation *alloc;
+ struct dxgallocation *tmp;
+ struct d3dkmt_destroyallocation2 args = { };
+ int destroyed = test_and_set_bit(0, &resource->flags);
+ struct dxgdevice *device = resource->device;
+ struct dxgsharedresource *shared_resource;
+
+ if (!destroyed) {
+ dxgresource_free_handle(resource);
+ if (resource->handle.v) {
+ args.device = device->handle;
+ args.resource = resource->handle;
+ dxgvmb_send_destroy_allocation(device->process,
+ device, &args, NULL);
+ resource->handle.v = 0;
+ }
+ list_for_each_entry_safe(alloc, tmp, &resource->alloc_list_head,
+ alloc_list_entry) {
+ dxgallocation_destroy(alloc);
+ }
+ dxgdevice_remove_resource(device, resource);
+ shared_resource = resource->shared_owner;
+ if (shared_resource) {
+ dxgsharedresource_remove_resource(shared_resource,
+ resource);
+ resource->shared_owner = NULL;
+ }
+ }
+ kref_put(&resource->resource_kref, dxgresource_release);
+}
+
+void dxgresource_release(struct kref *refcount)
+{
+ struct dxgresource *resource;
+
+ resource = container_of(refcount, struct dxgresource, resource_kref);
+ vfree(resource);
+}
+
+bool dxgresource_is_active(struct dxgresource *resource)
+{
+ return resource->object_state == DXGOBJECTSTATE_ACTIVE;
+}
+
+int dxgresource_add_alloc(struct dxgresource *resource,
+ struct dxgallocation *alloc)
+{
+ int ret = -ENODEV;
+ struct dxgdevice *device = resource->device;
+
+ dxgdevice_acquire_alloc_list_lock(device);
+ if (dxgresource_is_active(resource)) {
+ list_add_tail(&alloc->alloc_list_entry,
+ &resource->alloc_list_head);
+ alloc->owner.resource = resource;
+ ret = 0;
+ }
+ alloc->resource_owner = 1;
+ dxgdevice_release_alloc_list_lock(device);
+ return ret;
+}
+
+void dxgresource_remove_alloc(struct dxgresource *resource,
+ struct dxgallocation *alloc)
+{
+ if (alloc->alloc_list_entry.next) {
+ list_del(&alloc->alloc_list_entry);
+ alloc->alloc_list_entry.next = NULL;
+ }
+}
+
+void dxgresource_remove_alloc_safe(struct dxgresource *resource,
+ struct dxgallocation *alloc)
+{
+ dxgdevice_acquire_alloc_list_lock(resource->device);
+ dxgresource_remove_alloc(resource, alloc);
+ dxgdevice_release_alloc_list_lock(resource->device);
+}
+
void dxgdevice_release(struct kref *refcount)
{
struct dxgdevice *device;
@@ -522,6 +746,77 @@ void dxgcontext_release(struct kref *refcount)
vfree(context);
}
+struct dxgallocation *dxgallocation_create(struct dxgprocess *process)
+{
+ struct dxgallocation *alloc = vzalloc(sizeof(struct dxgallocation));
+
+ if (alloc)
+ alloc->process = process;
+ return alloc;
+}
+
+void dxgallocation_stop(struct dxgallocation *alloc)
+{
+ if (alloc->pages) {
+ release_pages(alloc->pages, alloc->num_pages);
+ vfree(alloc->pages);
+ alloc->pages = NULL;
+ }
+ dxgprocess_ht_lock_exclusive_down(alloc->process);
+ if (alloc->cpu_address_mapped) {
+ dxg_unmap_iospace(alloc->cpu_address,
+ alloc->num_pages << PAGE_SHIFT);
+ alloc->cpu_address_mapped = false;
+ alloc->cpu_address = NULL;
+ alloc->cpu_address_refcount = 0;
+ }
+ dxgprocess_ht_lock_exclusive_up(alloc->process);
+}
+
+void dxgallocation_free_handle(struct dxgallocation *alloc)
+{
+ dxgprocess_ht_lock_exclusive_down(alloc->process);
+ if (alloc->handle_valid) {
+ hmgrtable_free_handle(&alloc->process->handle_table,
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ alloc->alloc_handle);
+ alloc->handle_valid = 0;
+ }
+ dxgprocess_ht_lock_exclusive_up(alloc->process);
+}
+
+void dxgallocation_destroy(struct dxgallocation *alloc)
+{
+ struct dxgprocess *process = alloc->process;
+ struct d3dkmt_destroyallocation2 args = { };
+
+ dxgallocation_stop(alloc);
+ if (alloc->resource_owner)
+ dxgresource_remove_alloc(alloc->owner.resource, alloc);
+ else if (alloc->owner.device)
+ dxgdevice_remove_alloc(alloc->owner.device, alloc);
+ dxgallocation_free_handle(alloc);
+ if (alloc->alloc_handle.v && !alloc->resource_owner) {
+ args.device = alloc->owner.device->handle;
+ args.alloc_count = 1;
+ dxgvmb_send_destroy_allocation(process,
+ alloc->owner.device,
+ &args, &alloc->alloc_handle);
+ }
+ if (alloc->gpadl.gpadl_handle) {
+ dev_dbg(dxgglobaldev, "Teardown gpadl %d",
+ alloc->gpadl.gpadl_handle);
+ vmbus_teardown_gpadl(dxgglobal_get_vmbus(), &alloc->gpadl);
+ dev_dbg(dxgglobaldev, "Teardown gpadl end");
+ alloc->gpadl.gpadl_handle = 0;
+ }
+ if (alloc->priv_drv_data)
+ vfree(alloc->priv_drv_data);
+ if (alloc->cpu_address_mapped)
+ pr_err("Alloc IO space is mapped: %p", alloc);
+ vfree(alloc);
+}
+
struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
struct dxgadapter *adapter)
{
@@ -655,21 +950,6 @@ void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue)
/* Placeholder */
}
-void dxgallocation_destroy(struct dxgallocation *alloc)
-{
- /* Placeholder */
-}
-
-void dxgallocation_stop(struct dxgallocation *alloc)
-{
- /* Placeholder */
-}
-
-void dxgresource_destroy(struct dxgresource *resource)
-{
- /* Placeholder */
-}
-
void dxgsyncobject_destroy(struct dxgprocess *process,
struct dxgsyncobject *syncobj)
{
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 13dc34214f50..aba5f1cef431 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -18,6 +18,7 @@
#include <linux/hyperv.h>
#include <linux/mman.h>
#include <linux/delay.h>
+#include <linux/pagemap.h>
#include "dxgkrnl.h"
#include "dxgvmbus.h"
@@ -107,6 +108,40 @@ static int init_message(struct dxgvmbusmsg *msg, struct dxgadapter *adapter,
return 0;
}
+static int init_message_res(struct dxgvmbusmsgres *msg,
+ struct dxgadapter *adapter,
+ struct dxgprocess *process,
+ u32 size,
+ u32 result_size)
+{
+ bool use_ext_header = dxgglobal->vmbus_ver >=
+ DXGK_VMBUS_INTERFACE_VERSION;
+
+ if (use_ext_header)
+ size += sizeof(struct dxgvmb_ext_header);
+ msg->size = size;
+ msg->res_size += (result_size + 7) & ~7;
+ size += msg->res_size;
+ msg->hdr = vzalloc(size);
+ if (msg->hdr == NULL) {
+ pr_err("Failed to allocate VM bus message: %d", size);
+ return -ENOMEM;
+ }
+ if (use_ext_header) {
+ msg->msg = (char *)&msg->hdr[1];
+ msg->hdr->command_offset = sizeof(msg->hdr[0]);
+ msg->hdr->vgpu_luid = adapter->host_vgpu_luid;
+ } else {
+ msg->msg = (char *)msg->hdr;
+ }
+ msg->res = (char *)msg->hdr + msg->size;
+ if (dxgglobal->async_msg_enabled)
+ msg->channel = &dxgglobal->channel;
+ else
+ msg->channel = &adapter->channel;
+ return 0;
+}
+
static void free_message(struct dxgvmbusmsg *msg, struct dxgprocess *process)
{
if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
@@ -409,6 +444,26 @@ dxgvmb_send_sync_msg_ntstatus(struct dxgvmbuschannel *channel,
return ret;
}
+int dxg_unmap_iospace(void *va, u32 size)
+{
+ int ret = 0;
+
+ dev_dbg(dxgglobaldev, "%s %p %x", __func__, va, size);
+
+ /*
+ * When an app calls exit(), dxgkrnl is called to close the device
+ * with current->mm equal to NULL.
+ */
+ if (current->mm) {
+ ret = vm_munmap((unsigned long)va, size);
+ if (ret) {
+ pr_err("vm_munmap failed %d", ret);
+ return -ENOTRECOVERABLE;
+ }
+ }
+ return 0;
+}
+
/*
* Global messages to the host
*/
@@ -774,6 +829,616 @@ int dxgvmb_send_destroy_context(struct dxgadapter *adapter,
return ret;
}
+static int
+copy_private_data(struct d3dkmt_createallocation *args,
+ struct dxgkvmb_command_createallocation *command,
+ struct d3dddi_allocationinfo2 *input_alloc_info,
+ struct d3dkmt_createstandardallocation *standard_alloc)
+{
+ struct dxgkvmb_command_createallocation_allocinfo *alloc_info;
+ struct d3dddi_allocationinfo2 *input_alloc;
+ int ret = 0;
+ int i;
+ u8 *private_data_dest = (u8 *) &command[1] +
+ (args->alloc_count *
+ sizeof(struct dxgkvmb_command_createallocation_allocinfo));
+
+ if (args->private_runtime_data_size) {
+ ret = copy_from_user(private_data_dest,
+ args->private_runtime_data,
+ args->private_runtime_data_size);
+ if (ret) {
+ pr_err("%s failed to copy runtime data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ private_data_dest += args->private_runtime_data_size;
+ }
+
+ if (args->flags.standard_allocation) {
+ dev_dbg(dxgglobaldev, "private data offset %d",
+ (u32) (private_data_dest - (u8 *) command));
+
+ args->priv_drv_data_size = sizeof(*args->standard_allocation);
+ memcpy(private_data_dest, standard_alloc,
+ sizeof(*standard_alloc));
+ private_data_dest += args->priv_drv_data_size;
+ } else if (args->priv_drv_data_size) {
+ ret = copy_from_user(private_data_dest,
+ args->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy private data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ private_data_dest += args->priv_drv_data_size;
+ }
+
+ alloc_info = (void *)&command[1];
+ input_alloc = input_alloc_info;
+ if (input_alloc_info[0].sysmem)
+ command->flags.existing_sysmem = 1;
+ for (i = 0; i < args->alloc_count; i++) {
+ alloc_info->flags = input_alloc->flags.value;
+ alloc_info->vidpn_source_id = input_alloc->vidpn_source_id;
+ alloc_info->priv_drv_data_size =
+ input_alloc->priv_drv_data_size;
+ if (input_alloc->priv_drv_data_size) {
+ ret = copy_from_user(private_data_dest,
+ input_alloc->priv_drv_data,
+ input_alloc->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy alloc data",
+ __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ private_data_dest += input_alloc->priv_drv_data_size;
+ }
+ alloc_info++;
+ input_alloc++;
+ }
+
+cleanup:
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int create_existing_sysmem(struct dxgdevice *device,
+ struct dxgkvmb_command_allocinfo_return *host_alloc,
+ struct dxgallocation *dxgalloc,
+ bool read_only,
+ const void *sysmem)
+{
+ int ret1 = 0;
+ void *kmem = NULL;
+ int ret = 0;
+ struct dxgkvmb_command_setexistingsysmemstore *set_store_command;
+ u64 alloc_size = host_alloc->allocation_size;
+ u32 npages = alloc_size >> PAGE_SHIFT;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, device->adapter, device->process,
+ sizeof(*set_store_command));
+ if (ret)
+ goto cleanup;
+ set_store_command = (void *)msg.msg;
+
+ /*
+ * Create a guest physical address list and set it as the allocation
+ * backing store in the host. This is done after creating the host
+ * allocation, because only now the allocation size is known.
+ */
+
+ dev_dbg(dxgglobaldev, " Alloc size: %lld", alloc_size);
+
+ dxgalloc->cpu_address = (void *)sysmem;
+ dxgalloc->pages = vzalloc(npages * sizeof(void *));
+ if (dxgalloc->pages == NULL) {
+ pr_err("failed to allocate pages");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret1 = get_user_pages_fast((unsigned long)sysmem, npages, !read_only,
+ dxgalloc->pages);
+ if (ret1 != npages) {
+ pr_err("get_user_pages_fast failed: %d", ret1);
+ if (ret1 > 0 && ret1 < npages)
+ release_pages(dxgalloc->pages, ret1);
+ vfree(dxgalloc->pages);
+ dxgalloc->pages = NULL;
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
+ if (kmem == NULL) {
+ pr_err("vmap failed");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
+ alloc_size, &dxgalloc->gpadl);
+ if (ret1) {
+ pr_err("establish_gpadl failed: %d", ret1);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ dev_dbg(dxgglobaldev, "New gpadl %d", dxgalloc->gpadl.gpadl_handle);
+
+ command_vgpu_to_host_init2(&set_store_command->hdr,
+ DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
+ device->process->host_handle);
+ set_store_command->device = device->handle;
+ set_store_command->device = device->handle;
+ set_store_command->allocation = host_alloc->allocation;
+ set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+ if (ret < 0)
+ pr_err("failed to set existing store: %x", ret);
+
+cleanup:
+ if (kmem)
+ vunmap(kmem);
+ free_message(&msg, device->process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+static int
+process_allocation_handles(struct dxgprocess *process,
+ struct dxgdevice *device,
+ struct d3dkmt_createallocation *args,
+ struct dxgkvmb_command_createallocation_return *res,
+ struct dxgallocation **dxgalloc,
+ struct dxgresource *resource)
+{
+ int ret = 0;
+ int i;
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ if (args->flags.create_resource) {
+ ret = hmgrtable_assign_handle(&process->handle_table, resource,
+ HMGRENTRY_TYPE_DXGRESOURCE,
+ res->resource);
+ if (ret < 0) {
+ pr_err("failed to assign resource handle %x",
+ res->resource.v);
+ } else {
+ resource->handle = res->resource;
+ resource->handle_valid = 1;
+ }
+ }
+ for (i = 0; i < args->alloc_count; i++) {
+ struct dxgkvmb_command_allocinfo_return *host_alloc;
+
+ host_alloc = &res->allocation_info[i];
+ ret = hmgrtable_assign_handle(&process->handle_table,
+ dxgalloc[i],
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ host_alloc->allocation);
+ if (ret < 0) {
+ pr_err("failed to assign alloc handle %x %d %d",
+ host_alloc->allocation.v,
+ args->alloc_count, i);
+ break;
+ }
+ dxgalloc[i]->alloc_handle = host_alloc->allocation;
+ dxgalloc[i]->handle_valid = 1;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+static int
+create_local_allocations(struct dxgprocess *process,
+ struct dxgdevice *device,
+ struct d3dkmt_createallocation *args,
+ struct d3dkmt_createallocation *__user input_args,
+ struct d3dddi_allocationinfo2 *alloc_info,
+ struct dxgkvmb_command_createallocation_return *result,
+ struct dxgresource *resource,
+ struct dxgallocation **dxgalloc,
+ u32 destroy_buffer_size)
+{
+ int i;
+ int alloc_count = args->alloc_count;
+ u8 *alloc_private_data = NULL;
+ int ret = 0;
+ int ret1;
+ struct dxgkvmb_command_destroyallocation *destroy_buf;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, device->adapter, process,
+ destroy_buffer_size);
+ if (ret)
+ goto cleanup;
+ destroy_buf = (void *)msg.msg;
+
+ /* Prepare the command to destroy allocation in case of failure */
+ command_vgpu_to_host_init2(&destroy_buf->hdr,
+ DXGK_VMBCOMMAND_DESTROYALLOCATION,
+ process->host_handle);
+ destroy_buf->device = args->device;
+ destroy_buf->resource = args->resource;
+ destroy_buf->alloc_count = alloc_count;
+ destroy_buf->flags.assume_not_in_use = 1;
+ for (i = 0; i < alloc_count; i++) {
+ dev_dbg(dxgglobaldev, "host allocation: %d %x",
+ i, result->allocation_info[i].allocation.v);
+ destroy_buf->allocations[i] =
+ result->allocation_info[i].allocation;
+ }
+
+ if (args->flags.create_resource) {
+ dev_dbg(dxgglobaldev, "new resource: %x", result->resource.v);
+ ret = copy_to_user(&input_args->resource, &result->resource,
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy resource handle", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ alloc_private_data = (u8 *) result +
+ sizeof(struct dxgkvmb_command_createallocation_return) +
+ sizeof(struct dxgkvmb_command_allocinfo_return) * (alloc_count - 1);
+
+ for (i = 0; i < alloc_count; i++) {
+ struct dxgkvmb_command_allocinfo_return *host_alloc;
+ struct d3dddi_allocationinfo2 *user_alloc;
+
+ host_alloc = &result->allocation_info[i];
+ user_alloc = &alloc_info[i];
+ dxgalloc[i]->num_pages =
+ host_alloc->allocation_size >> PAGE_SHIFT;
+ if (user_alloc->sysmem) {
+ ret = create_existing_sysmem(device, host_alloc,
+ dxgalloc[i],
+ args->flags.read_only != 0,
+ user_alloc->sysmem);
+ if (ret < 0)
+ goto cleanup;
+ }
+ dxgalloc[i]->cached = host_alloc->allocation_flags.cached;
+ if (host_alloc->priv_drv_data_size) {
+ ret = copy_to_user(user_alloc->priv_drv_data,
+ alloc_private_data,
+ host_alloc->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy private data",
+ __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ alloc_private_data += host_alloc->priv_drv_data_size;
+ }
+ ret = copy_to_user(&args->allocation_info[i].allocation,
+ &host_alloc->allocation,
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy alloc handle", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ ret = process_allocation_handles(process, device, args, result,
+ dxgalloc, resource);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(&input_args->global_share, &args->global_share,
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy global share", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (ret < 0) {
+ /* Free local handles before freeing the handles in the host */
+ dxgdevice_acquire_alloc_list_lock(device);
+ if (dxgalloc)
+ for (i = 0; i < alloc_count; i++)
+ if (dxgalloc[i])
+ dxgallocation_free_handle(dxgalloc[i]);
+ if (resource && args->flags.create_resource)
+ dxgresource_free_handle(resource);
+ dxgdevice_release_alloc_list_lock(device);
+
+ /* Destroy allocations in the host to unmap gpadls */
+ ret1 = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
+ msg.size);
+ if (ret1 < 0)
+ pr_err("failed to destroy allocations: %x", ret1);
+
+ dxgdevice_acquire_alloc_list_lock(device);
+ if (dxgalloc) {
+ for (i = 0; i < alloc_count; i++) {
+ if (dxgalloc[i]) {
+ dxgalloc[i]->alloc_handle.v = 0;
+ dxgallocation_destroy(dxgalloc[i]);
+ dxgalloc[i] = NULL;
+ }
+ }
+ }
+ if (resource && args->flags.create_resource) {
+ /*
+ * Prevent the resource memory from freeing.
+ * It will be freed in the top level function.
+ */
+ kref_get(&resource->resource_kref);
+ dxgresource_destroy(resource);
+ }
+ dxgdevice_release_alloc_list_lock(device);
+ }
+
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_create_allocation(struct dxgprocess *process,
+ struct dxgdevice *device,
+ struct d3dkmt_createallocation *args,
+ struct d3dkmt_createallocation *__user
+ input_args,
+ struct dxgresource *resource,
+ struct dxgallocation **dxgalloc,
+ struct d3dddi_allocationinfo2 *alloc_info,
+ struct d3dkmt_createstandardallocation
+ *standard_alloc)
+{
+ struct dxgkvmb_command_createallocation *command = NULL;
+ struct dxgkvmb_command_createallocation_return *result = NULL;
+ int ret = -EINVAL;
+ int i;
+ u32 result_size = 0;
+ u32 cmd_size = 0;
+ u32 destroy_buffer_size = 0;
+ u32 priv_drv_data_size;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ if (args->private_runtime_data_size >= DXG_MAX_VM_BUS_PACKET_SIZE ||
+ args->priv_drv_data_size >= DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EOVERFLOW;
+ goto cleanup;
+ }
+
+ /*
+ * Preallocate the buffer, which will be used for destruction in case
+ * of a failure
+ */
+ destroy_buffer_size = sizeof(struct dxgkvmb_command_destroyallocation) +
+ args->alloc_count * sizeof(struct d3dkmthandle);
+
+ /* Compute the total private driver size */
+
+ priv_drv_data_size = 0;
+
+ for (i = 0; i < args->alloc_count; i++) {
+ if (alloc_info[i].priv_drv_data_size >=
+ DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EOVERFLOW;
+ goto cleanup;
+ } else {
+ priv_drv_data_size += alloc_info[i].priv_drv_data_size;
+ }
+ if (priv_drv_data_size >= DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EOVERFLOW;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Private driver data for the result includes only per allocation
+ * private data
+ */
+ result_size = sizeof(struct dxgkvmb_command_createallocation_return) +
+ (args->alloc_count - 1) *
+ sizeof(struct dxgkvmb_command_allocinfo_return) +
+ priv_drv_data_size;
+ result = vzalloc(result_size);
+ if (result == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* Private drv data for the command includes the global private data */
+ priv_drv_data_size += args->priv_drv_data_size;
+
+ cmd_size = sizeof(struct dxgkvmb_command_createallocation) +
+ args->alloc_count *
+ sizeof(struct dxgkvmb_command_createallocation_allocinfo) +
+ args->private_runtime_data_size + priv_drv_data_size;
+ if (cmd_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EOVERFLOW;
+ goto cleanup;
+ }
+
+ dev_dbg(dxgglobaldev, "command size, driver_data_size %d %d %ld %ld",
+ cmd_size, priv_drv_data_size,
+ sizeof(struct dxgkvmb_command_createallocation),
+ sizeof(struct dxgkvmb_command_createallocation_allocinfo));
+
+ ret = init_message(&msg, device->adapter, process,
+ cmd_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_CREATEALLOCATION,
+ process->host_handle);
+ command->device = args->device;
+ command->flags = args->flags;
+ command->resource = args->resource;
+ command->private_runtime_resource_handle =
+ args->private_runtime_resource_handle;
+ command->alloc_count = args->alloc_count;
+ command->private_runtime_data_size = args->private_runtime_data_size;
+ command->priv_drv_data_size = args->priv_drv_data_size;
+
+ ret = copy_private_data(args, command, alloc_info, standard_alloc);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ result, result_size);
+ if (ret < 0) {
+ pr_err("send_create_allocation failed %x", ret);
+ goto cleanup;
+ }
+
+ ret = create_local_allocations(process, device, args, input_args,
+ alloc_info, result, resource, dxgalloc,
+ destroy_buffer_size);
+cleanup:
+
+ if (result)
+ vfree(result);
+ free_message(&msg, process);
+
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_destroy_allocation(struct dxgprocess *process,
+ struct dxgdevice *device,
+ struct d3dkmt_destroyallocation2 *args,
+ struct d3dkmthandle *alloc_handles)
+{
+ struct dxgkvmb_command_destroyallocation *destroy_buffer;
+ u32 destroy_buffer_size;
+ int ret;
+ int allocations_size = args->alloc_count * sizeof(struct d3dkmthandle);
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ destroy_buffer_size = sizeof(struct dxgkvmb_command_destroyallocation) +
+ allocations_size;
+
+ ret = init_message(&msg, device->adapter, process,
+ destroy_buffer_size);
+ if (ret)
+ goto cleanup;
+ destroy_buffer = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&destroy_buffer->hdr,
+ DXGK_VMBCOMMAND_DESTROYALLOCATION,
+ process->host_handle);
+ destroy_buffer->device = args->device;
+ destroy_buffer->resource = args->resource;
+ destroy_buffer->alloc_count = args->alloc_count;
+ destroy_buffer->flags = args->flags;
+ if (allocations_size)
+ memcpy(destroy_buffer->allocations, alloc_handles,
+ allocations_size);
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
+ enum d3dkmdt_standardallocationtype alloctype,
+ struct d3dkmdt_gdisurfacedata *alloc_data,
+ u32 physical_adapter_index,
+ u32 *alloc_priv_driver_size,
+ void *priv_alloc_data,
+ u32 *res_priv_data_size,
+ void *priv_res_data)
+{
+ struct dxgkvmb_command_getstandardallocprivdata *command;
+ struct dxgkvmb_command_getstandardallocprivdata_return *result = NULL;
+ u32 result_size = sizeof(*result);
+ int ret;
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
+
+ if (priv_alloc_data)
+ result_size += *alloc_priv_driver_size;
+ if (priv_res_data)
+ result_size += *res_priv_data_size;
+ ret = init_message_res(&msg, device->adapter, device->process,
+ sizeof(*command), result_size);
+ if (ret)
+ goto cleanup;
+ command = msg.msg;
+ result = msg.res;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_DDIGETSTANDARDALLOCATIONDRIVERDATA,
+ device->process->host_handle);
+
+ command->alloc_type = alloctype;
+ command->priv_driver_data_size = *alloc_priv_driver_size;
+ command->physical_adapter_index = physical_adapter_index;
+ command->priv_driver_resource_size = *res_priv_data_size;
+ switch (alloctype) {
+ case _D3DKMDT_STANDARDALLOCATION_GDISURFACE:
+ command->gdi_surface = *alloc_data;
+ break;
+ case _D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE:
+ case _D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE:
+ case _D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE:
+ default:
+ pr_err("Invalid standard alloc type");
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ result, msg.res_size);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(result->status);
+ if (ret < 0)
+ goto cleanup;
+
+ if (*alloc_priv_driver_size &&
+ result->priv_driver_data_size != *alloc_priv_driver_size) {
+ pr_err("Priv data size mismatch");
+ goto cleanup;
+ }
+ if (*res_priv_data_size &&
+ result->priv_driver_resource_size != *res_priv_data_size) {
+ pr_err("Resource priv data size mismatch");
+ goto cleanup;
+ }
+ *alloc_priv_driver_size = result->priv_driver_data_size;
+ *res_priv_data_size = result->priv_driver_resource_size;
+ if (priv_alloc_data) {
+ memcpy(priv_alloc_data, &result[1],
+ result->priv_driver_data_size);
+ }
+ if (priv_res_data) {
+ memcpy(priv_res_data,
+ (char *)(&result[1]) + result->priv_driver_data_size,
+ result->priv_driver_resource_size);
+ }
+
+cleanup:
+
+ free_message((struct dxgvmbusmsg *)&msg, device->process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, 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/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 590ce9bfa592..79dc22379ec4 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -751,6 +751,735 @@ static int dxgk_destroy_hwcontext(struct dxgprocess *process,
return -ENOTTY;
}
+static int
+get_standard_alloc_priv_data(struct dxgdevice *device,
+ struct d3dkmt_createstandardallocation *alloc_info,
+ u32 *standard_alloc_priv_data_size,
+ void **standard_alloc_priv_data,
+ u32 *standard_res_priv_data_size,
+ void **standard_res_priv_data)
+{
+ int ret;
+ struct d3dkmdt_gdisurfacedata gdi_data = { };
+ u32 priv_data_size = 0;
+ u32 res_priv_data_size = 0;
+ void *priv_data = NULL;
+ void *res_priv_data = NULL;
+
+ gdi_data.type = _D3DKMDT_GDISURFACE_TEXTURE_CROSSADAPTER;
+ gdi_data.width = alloc_info->existing_heap_data.size;
+ gdi_data.height = 1;
+ gdi_data.format = _D3DDDIFMT_UNKNOWN;
+
+ *standard_alloc_priv_data_size = 0;
+ ret = dxgvmb_send_get_stdalloc_data(device,
+ _D3DKMDT_STANDARDALLOCATION_GDISURFACE,
+ &gdi_data, 0,
+ &priv_data_size, NULL,
+ &res_priv_data_size,
+ NULL);
+ if (ret < 0)
+ goto cleanup;
+ dev_dbg(dxgglobaldev, "Priv data size: %d", priv_data_size);
+ if (priv_data_size == 0) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ priv_data = vzalloc(priv_data_size);
+ if (priv_data == NULL) {
+ ret = -ENOMEM;
+ pr_err("failed to allocate memory for priv data: %d",
+ priv_data_size);
+ goto cleanup;
+ }
+ if (res_priv_data_size) {
+ res_priv_data = vzalloc(res_priv_data_size);
+ if (res_priv_data == NULL) {
+ ret = -ENOMEM;
+ pr_err("failed to alloc memory for res priv data: %d",
+ res_priv_data_size);
+ goto cleanup;
+ }
+ }
+ ret = dxgvmb_send_get_stdalloc_data(device,
+ _D3DKMDT_STANDARDALLOCATION_GDISURFACE,
+ &gdi_data, 0,
+ &priv_data_size,
+ priv_data,
+ &res_priv_data_size,
+ res_priv_data);
+ if (ret < 0)
+ goto cleanup;
+ *standard_alloc_priv_data_size = priv_data_size;
+ *standard_alloc_priv_data = priv_data;
+ *standard_res_priv_data_size = res_priv_data_size;
+ *standard_res_priv_data = res_priv_data;
+ priv_data = NULL;
+ res_priv_data = NULL;
+
+cleanup:
+ if (priv_data)
+ vfree(priv_data);
+ if (res_priv_data)
+ vfree(res_priv_data);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_create_allocation(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_createallocation args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ struct d3dddi_allocationinfo2 *alloc_info = NULL;
+ struct d3dkmt_createstandardallocation standard_alloc;
+ u32 alloc_info_size = 0;
+ struct dxgresource *resource = NULL;
+ struct dxgallocation **dxgalloc = NULL;
+ struct dxgsharedresource *shared_resource = NULL;
+ bool resource_mutex_acquired = false;
+ u32 standard_alloc_priv_data_size = 0;
+ void *standard_alloc_priv_data = NULL;
+ u32 res_priv_data_size = 0;
+ void *res_priv_data = NULL;
+ int i;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.alloc_count > D3DKMT_CREATEALLOCATION_MAX ||
+ args.alloc_count == 0) {
+ pr_err("invalid number of allocations to create");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ alloc_info_size = sizeof(struct d3dddi_allocationinfo2) *
+ args.alloc_count;
+ alloc_info = vzalloc(alloc_info_size);
+ if (alloc_info == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret = copy_from_user(alloc_info, args.allocation_info,
+ alloc_info_size);
+ if (ret) {
+ pr_err("%s failed to copy alloc info", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ for (i = 0; i < args.alloc_count; i++) {
+ if (args.flags.standard_allocation) {
+ if (alloc_info[i].priv_drv_data_size != 0) {
+ pr_err("private data size is not zero");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+ if (alloc_info[i].priv_drv_data_size >=
+ DXG_MAX_VM_BUS_PACKET_SIZE) {
+ pr_err("private data size is too big: %d %d %ld",
+ i, alloc_info[i].priv_drv_data_size,
+ sizeof(alloc_info[0]));
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ if (args.flags.existing_section || args.flags.create_protected) {
+ pr_err("invalid allocation flags");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.flags.standard_allocation) {
+ if (args.standard_allocation == NULL) {
+ pr_err("invalid standard allocation");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_from_user(&standard_alloc,
+ args.standard_allocation,
+ sizeof(standard_alloc));
+ if (ret) {
+ pr_err("%s failed to copy std alloc data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (standard_alloc.type ==
+ _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP) {
+ if (alloc_info[0].sysmem == NULL ||
+ (unsigned long)alloc_info[0].sysmem &
+ (PAGE_SIZE - 1)) {
+ pr_err("invalid sysmem pointer");
+ ret = STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+ if (!args.flags.existing_sysmem) {
+ pr_err("expected existing_sysmem flag");
+ ret = STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+ } else if (standard_alloc.type ==
+ _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER) {
+ if (args.flags.existing_sysmem) {
+ pr_err("existing_sysmem flag is invalid");
+ ret = STATUS_INVALID_PARAMETER;
+ goto cleanup;
+
+ }
+ if (alloc_info[0].sysmem != NULL) {
+ pr_err("sysmem should be NULL");
+ ret = STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+ } else {
+ pr_err("invalid standard allocation type");
+ ret = STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ if (args.priv_drv_data_size != 0 ||
+ args.alloc_count != 1 ||
+ standard_alloc.existing_heap_data.size == 0 ||
+ standard_alloc.existing_heap_data.size & (PAGE_SIZE - 1)) {
+ pr_err("invalid standard allocation");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ args.priv_drv_data_size =
+ sizeof(struct d3dkmt_createstandardallocation);
+ }
+
+ if (args.flags.create_shared && !args.flags.create_resource) {
+ pr_err("create_resource must be set for create_shared");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ kref_put(&device->device_kref, dxgdevice_release);
+ device = NULL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ if (args.flags.standard_allocation) {
+ ret = get_standard_alloc_priv_data(device,
+ &standard_alloc,
+ &standard_alloc_priv_data_size,
+ &standard_alloc_priv_data,
+ &res_priv_data_size,
+ &res_priv_data);
+ if (ret < 0)
+ goto cleanup;
+ dev_dbg(dxgglobaldev, "Alloc private data: %d",
+ standard_alloc_priv_data_size);
+ }
+
+ if (args.flags.create_resource) {
+ resource = dxgresource_create(device);
+ if (resource == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ resource->private_runtime_handle =
+ args.private_runtime_resource_handle;
+ if (args.flags.create_shared) {
+ if (!args.flags.nt_security_sharing) {
+ dev_err(dxgglobaldev,
+ "%s: nt_security_sharing must be set",
+ __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ shared_resource = dxgsharedresource_create(adapter);
+ if (shared_resource == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ shared_resource->runtime_private_data_size =
+ args.priv_drv_data_size;
+ shared_resource->resource_private_data_size =
+ args.priv_drv_data_size;
+
+ shared_resource->runtime_private_data_size =
+ args.private_runtime_data_size;
+ shared_resource->resource_private_data_size =
+ args.priv_drv_data_size;
+ dxgsharedresource_add_resource(shared_resource,
+ resource);
+ if (args.flags.standard_allocation) {
+ shared_resource->resource_private_data =
+ res_priv_data;
+ shared_resource->resource_private_data_size =
+ res_priv_data_size;
+ res_priv_data = NULL;
+ }
+ if (args.private_runtime_data_size) {
+ shared_resource->runtime_private_data =
+ vzalloc(args.private_runtime_data_size);
+ if (shared_resource->runtime_private_data ==
+ NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret = copy_from_user(
+ shared_resource->runtime_private_data,
+ args.private_runtime_data,
+ args.private_runtime_data_size);
+ if (ret) {
+ pr_err("%s failed to copy runtime data",
+ __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+ if (args.priv_drv_data_size &&
+ !args.flags.standard_allocation) {
+ shared_resource->resource_private_data =
+ vzalloc(args.priv_drv_data_size);
+ if (shared_resource->resource_private_data ==
+ NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret = copy_from_user(
+ shared_resource->resource_private_data,
+ args.priv_drv_data,
+ args.priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy res data",
+ __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+ }
+ } else {
+ if (args.resource.v) {
+ /* Adding new allocations to the given resource */
+
+ dxgprocess_ht_lock_shared_down(process);
+ resource = hmgrtable_get_object_by_type(
+ &process->handle_table,
+ HMGRENTRY_TYPE_DXGRESOURCE,
+ args.resource);
+ kref_get(&resource->resource_kref);
+ dxgprocess_ht_lock_shared_up(process);
+
+ if (resource == NULL || resource->device != device) {
+ pr_err("invalid resource handle %x",
+ args.resource.v);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (resource->shared_owner &&
+ resource->shared_owner->sealed) {
+ pr_err("Resource is sealed");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ /* Synchronize with resource destruction */
+ mutex_lock(&resource->resource_mutex);
+ if (!dxgresource_is_active(resource)) {
+ mutex_unlock(&resource->resource_mutex);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ resource_mutex_acquired = true;
+ }
+ }
+
+ dxgalloc = vzalloc(sizeof(struct dxgallocation *) * args.alloc_count);
+ if (dxgalloc == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ for (i = 0; i < args.alloc_count; i++) {
+ struct dxgallocation *alloc;
+ u32 priv_data_size;
+
+ if (args.flags.standard_allocation)
+ priv_data_size = standard_alloc_priv_data_size;
+ else
+ priv_data_size = alloc_info[i].priv_drv_data_size;
+
+ if (alloc_info[i].sysmem && !args.flags.standard_allocation) {
+ if ((unsigned long)
+ alloc_info[i].sysmem & (PAGE_SIZE - 1)) {
+ pr_err("invalid sysmem alloc %d, %p",
+ i, alloc_info[i].sysmem);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+ if ((alloc_info[0].sysmem == NULL) !=
+ (alloc_info[i].sysmem == NULL)) {
+ pr_err("All allocations must have sysmem pointer");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dxgalloc[i] = dxgallocation_create(process);
+ if (dxgalloc[i] == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ alloc = dxgalloc[i];
+
+ if (resource) {
+ ret = dxgresource_add_alloc(resource, alloc);
+ if (ret < 0)
+ goto cleanup;
+ } else {
+ dxgdevice_add_alloc(device, alloc);
+ }
+ if (args.flags.create_shared) {
+ /* Remember alloc private data to use it during open */
+ alloc->priv_drv_data = vzalloc(priv_data_size +
+ offsetof(struct privdata, data) - 1);
+ if (alloc->priv_drv_data == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ if (args.flags.standard_allocation) {
+ memcpy(alloc->priv_drv_data->data,
+ standard_alloc_priv_data,
+ standard_alloc_priv_data_size);
+ alloc->priv_drv_data->data_size =
+ standard_alloc_priv_data_size;
+ } else {
+ ret = copy_from_user(
+ alloc->priv_drv_data->data,
+ alloc_info[i].priv_drv_data,
+ priv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy priv data",
+ __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ alloc->priv_drv_data->data_size =
+ priv_data_size;
+ }
+ }
+ }
+
+ ret = dxgvmb_send_create_allocation(process, device, &args, inargs,
+ resource, dxgalloc, alloc_info,
+ &standard_alloc);
+cleanup:
+
+ if (resource_mutex_acquired) {
+ mutex_unlock(&resource->resource_mutex);
+ kref_put(&resource->resource_kref, dxgresource_release);
+ }
+ if (ret < 0) {
+ if (dxgalloc) {
+ for (i = 0; i < args.alloc_count; i++) {
+ if (dxgalloc[i])
+ dxgallocation_destroy(dxgalloc[i]);
+ }
+ }
+ if (resource && args.flags.create_resource) {
+ if (shared_resource) {
+ dxgsharedresource_remove_resource
+ (shared_resource, resource);
+ }
+ dxgresource_destroy(resource);
+ }
+ }
+ if (shared_resource)
+ kref_put(&shared_resource->sresource_kref,
+ dxgsharedresource_destroy);
+ if (dxgalloc)
+ vfree(dxgalloc);
+ if (standard_alloc_priv_data)
+ vfree(standard_alloc_priv_data);
+ if (res_priv_data)
+ vfree(res_priv_data);
+ if (alloc_info)
+ vfree(alloc_info);
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device) {
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+int validate_alloc(struct dxgallocation *alloc0,
+ struct dxgallocation *alloc,
+ struct dxgdevice *device,
+ struct d3dkmthandle alloc_handle)
+{
+ u32 fail_reason;
+
+ if (alloc == NULL) {
+ fail_reason = 1;
+ goto cleanup;
+ }
+ if (alloc->resource_owner != alloc0->resource_owner) {
+ fail_reason = 2;
+ goto cleanup;
+ }
+ if (alloc->resource_owner) {
+ if (alloc->owner.resource != alloc0->owner.resource) {
+ fail_reason = 3;
+ goto cleanup;
+ }
+ if (alloc->owner.resource->device != device) {
+ fail_reason = 4;
+ goto cleanup;
+ }
+ if (alloc->owner.resource->shared_owner) {
+ fail_reason = 5;
+ goto cleanup;
+ }
+ } else {
+ if (alloc->owner.device != device) {
+ fail_reason = 6;
+ goto cleanup;
+ }
+ }
+ return 0;
+cleanup:
+ pr_err("Alloc validation failed: reason: %d %x",
+ fail_reason, alloc_handle.v);
+ return -EINVAL;
+}
+
+static int
+dxgk_destroy_allocation(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_destroyallocation2 args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ int ret;
+ struct d3dkmthandle *alloc_handles = NULL;
+ struct dxgallocation **allocs = NULL;
+ struct dxgresource *resource = NULL;
+ int i;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.alloc_count > D3DKMT_CREATEALLOCATION_MAX ||
+ ((args.alloc_count == 0) == (args.resource.v == 0))) {
+ pr_err("invalid number of allocations");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.alloc_count) {
+ u32 handle_size = sizeof(struct d3dkmthandle) *
+ args.alloc_count;
+
+ alloc_handles = vzalloc(handle_size);
+ if (alloc_handles == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ allocs = vzalloc(sizeof(struct dxgallocation *) *
+ args.alloc_count);
+ if (allocs == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret = copy_from_user(alloc_handles, args.allocations,
+ handle_size);
+ if (ret) {
+ pr_err("%s failed to copy alloc handles", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /* Acquire the device lock to synchronize with the device destriction */
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ kref_put(&device->device_kref, dxgdevice_release);
+ device = NULL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ /*
+ * Destroy the local allocation handles first. If the host handle
+ * is destroyed first, another object could be assigned to the process
+ * table at the same place as the allocation handle and it will fail.
+ */
+ if (args.alloc_count) {
+ dxgprocess_ht_lock_exclusive_down(process);
+ for (i = 0; i < args.alloc_count; i++) {
+ allocs[i] =
+ hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ alloc_handles[i]);
+ ret =
+ validate_alloc(allocs[0], allocs[i], device,
+ alloc_handles[i]);
+ if (ret < 0) {
+ dxgprocess_ht_lock_exclusive_up(process);
+ goto cleanup;
+ }
+ }
+ dxgprocess_ht_lock_exclusive_up(process);
+ for (i = 0; i < args.alloc_count; i++)
+ dxgallocation_free_handle(allocs[i]);
+ } else {
+ struct dxgallocation *alloc;
+
+ dxgprocess_ht_lock_exclusive_down(process);
+ resource = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGRESOURCE,
+ args.resource);
+ if (resource == NULL) {
+ pr_err("Invalid resource handle: %x",
+ args.resource.v);
+ ret = -EINVAL;
+ } else if (resource->device != device) {
+ pr_err("Resource belongs to wrong device: %x",
+ args.resource.v);
+ ret = -EINVAL;
+ } else {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGRESOURCE,
+ args.resource);
+ resource->object_state = DXGOBJECTSTATE_DESTROYED;
+ resource->handle.v = 0;
+ resource->handle_valid = 0;
+ }
+ dxgprocess_ht_lock_exclusive_up(process);
+
+ if (ret < 0)
+ goto cleanup;
+
+ dxgdevice_acquire_alloc_list_lock_shared(device);
+ list_for_each_entry(alloc, &resource->alloc_list_head,
+ alloc_list_entry) {
+ dxgallocation_free_handle(alloc);
+ }
+ dxgdevice_release_alloc_list_lock_shared(device);
+ }
+
+ if (args.alloc_count && allocs[0]->resource_owner)
+ resource = allocs[0]->owner.resource;
+
+ if (resource) {
+ kref_get(&resource->resource_kref);
+ mutex_lock(&resource->resource_mutex);
+ }
+
+ ret = dxgvmb_send_destroy_allocation(process, device, &args,
+ alloc_handles);
+
+ /*
+ * Destroy the allocations after the host destroyed it.
+ * The allocation gpadl teardown will wait until the host unmaps its
+ * gpadl.
+ */
+ dxgdevice_acquire_alloc_list_lock(device);
+ if (args.alloc_count) {
+ for (i = 0; i < args.alloc_count; i++) {
+ if (allocs[i]) {
+ allocs[i]->alloc_handle.v = 0;
+ dxgallocation_destroy(allocs[i]);
+ }
+ }
+ } else {
+ dxgresource_destroy(resource);
+ }
+ dxgdevice_release_alloc_list_lock(device);
+
+ if (resource) {
+ mutex_unlock(&resource->resource_mutex);
+ kref_put(&resource->resource_kref, dxgresource_release);
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device) {
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+
+ if (alloc_handles)
+ vfree(alloc_handles);
+
+ if (allocs)
+ vfree(allocs);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_render(struct dxgprocess *process, void *__user inargs)
+{
+ pr_err("%s is not implemented", __func__);
+ return -ENOTTY;
+}
+
static int
dxgk_create_context(struct dxgprocess *process, void *__user inargs)
{
@@ -758,6 +1487,14 @@ dxgk_create_context(struct dxgprocess *process, void *__user inargs)
return -ENOTTY;
}
+static int
+dxgk_get_shared_resource_adapter_luid(struct dxgprocess *process,
+ void *__user inargs)
+{
+ pr_err("shared_resource_adapter_luid is not implemented");
+ return -ENOTTY;
+}
+
/*
* IOCTL processing
* The driver IOCTLs return
@@ -824,8 +1561,12 @@ void init_ioctls(void)
LX_DXCREATECONTEXTVIRTUAL);
SET_IOCTL(/*0x5 */ dxgk_destroy_context,
LX_DXDESTROYCONTEXT);
+ SET_IOCTL(/*0x6 */ dxgk_create_allocation,
+ LX_DXCREATEALLOCATION);
SET_IOCTL(/*0x9 */ dxgk_query_adapter_info,
LX_DXQUERYADAPTERINFO);
+ SET_IOCTL(/*0x13 */ dxgk_destroy_allocation,
+ LX_DXDESTROYALLOCATION2);
SET_IOCTL(/*0x14 */ dxgk_enum_adapters,
LX_DXENUMADAPTERS2);
SET_IOCTL(/*0x15 */ dxgk_close_adapter,
@@ -836,6 +1577,10 @@ void init_ioctls(void)
LX_DXDESTROYDEVICE);
SET_IOCTL(/*0x1a */ dxgk_destroy_hwcontext,
LX_DXDESTROYHWCONTEXT);
+ SET_IOCTL(/*0x23 */ dxgk_get_shared_resource_adapter_luid,
+ LX_DXGETSHAREDRESOURCEADAPTERLUID);
+ SET_IOCTL(/*0x2d */ dxgk_render,
+ LX_DXRENDER);
SET_IOCTL(/*0x3e */ dxgk_enum_adapters3,
LX_DXENUMADAPTERS3);
}
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v1 3/9] drivers: hv: dxgkrnl: Implement creation/destruction of GPU allocations/resources
2022-01-12 19:55 ` [PATCH v1 3/9] drivers: hv: dxgkrnl: Implement creation/destruction of GPU allocations/resources Iouri Tarassov
@ 2022-01-13 8:56 ` kernel test robot
0 siblings, 0 replies; 33+ messages in thread
From: kernel test robot @ 2022-01-13 8:56 UTC (permalink / raw)
To: Iouri Tarassov, kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: llvm, kbuild-all, linux-kernel, spronovo, gregkh
Hi Iouri,
I love your patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v5.16 next-20220113]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git e3084ed48fd6b661fe434da0cb36d7d6706cf27f
config: arm64-randconfig-r032-20220113 (https://download.01.org/0day-ci/archive/20220113/202201131642.1nercfCr-lkp@intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project d1021978b8e7e35dcc30201ca1731d64b5a602a8)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm64 cross compiling tool for clang build
# apt-get install binutils-aarch64-linux-gnu
# https://github.com/0day-ci/linux/commit/a2aa8c606c48a4e6bf8a7a51e2e4e5738e35da32
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
git checkout a2aa8c606c48a4e6bf8a7a51e2e4e5738e35da32
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/hv/dxgkrnl/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
In file included from drivers/hv/dxgkrnl/ioctl.c:21:
drivers/hv/dxgkrnl/dxgvmbus.h:867:26: warning: implicit conversion from enumeration type 'enum dxgkvmb_commandtype' to different enumeration type 'enum dxgkvmb_commandtype_global' [-Wenum-conversion]
command->command_type = DXGK_VMBCOMMAND_INVALID;
~ ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/hv/dxgkrnl/ioctl.c:1245:5: warning: no previous prototype for function 'validate_alloc' [-Wmissing-prototypes]
int validate_alloc(struct dxgallocation *alloc0,
^
drivers/hv/dxgkrnl/ioctl.c:1245:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int validate_alloc(struct dxgallocation *alloc0,
^
static
2 warnings generated.
--
In file included from drivers/hv/dxgkrnl/dxgvmbus.c:23:
drivers/hv/dxgkrnl/dxgvmbus.h:867:26: warning: implicit conversion from enumeration type 'enum dxgkvmb_commandtype' to different enumeration type 'enum dxgkvmb_commandtype_global' [-Wenum-conversion]
command->command_type = DXGK_VMBCOMMAND_INVALID;
~ ^~~~~~~~~~~~~~~~~~~~~~~
drivers/hv/dxgkrnl/dxgvmbus.c:151:5: warning: no previous prototype for function 'ntstatus2int' [-Wmissing-prototypes]
int ntstatus2int(struct ntstatus status)
^
drivers/hv/dxgkrnl/dxgvmbus.c:151:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int ntstatus2int(struct ntstatus status)
^
static
drivers/hv/dxgkrnl/dxgvmbus.c:254:6: warning: no previous prototype for function 'process_inband_packet' [-Wmissing-prototypes]
void process_inband_packet(struct dxgvmbuschannel *channel,
^
drivers/hv/dxgkrnl/dxgvmbus.c:254:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void process_inband_packet(struct dxgvmbuschannel *channel,
^
static
drivers/hv/dxgkrnl/dxgvmbus.c:272:6: warning: no previous prototype for function 'process_completion_packet' [-Wmissing-prototypes]
void process_completion_packet(struct dxgvmbuschannel *channel,
^
drivers/hv/dxgkrnl/dxgvmbus.c:272:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void process_completion_packet(struct dxgvmbuschannel *channel,
^
static
drivers/hv/dxgkrnl/dxgvmbus.c:398:5: warning: no previous prototype for function 'dxgvmb_send_async_msg' [-Wmissing-prototypes]
int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
^
drivers/hv/dxgkrnl/dxgvmbus.c:398:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
^
static
>> drivers/hv/dxgkrnl/dxgvmbus.c:909:5: warning: no previous prototype for function 'create_existing_sysmem' [-Wmissing-prototypes]
int create_existing_sysmem(struct dxgdevice *device,
^
drivers/hv/dxgkrnl/dxgvmbus.c:909:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int create_existing_sysmem(struct dxgdevice *device,
^
static
drivers/hv/dxgkrnl/dxgvmbus.c:234:20: warning: unused function 'command_vm_to_host_init0' [-Wunused-function]
static inline void command_vm_to_host_init0(struct dxgkvmb_command_vm_to_host
^
7 warnings generated.
vim +/validate_alloc +1245 drivers/hv/dxgkrnl/ioctl.c
1244
> 1245 int validate_alloc(struct dxgallocation *alloc0,
1246 struct dxgallocation *alloc,
1247 struct dxgdevice *device,
1248 struct d3dkmthandle alloc_handle)
1249 {
1250 u32 fail_reason;
1251
1252 if (alloc == NULL) {
1253 fail_reason = 1;
1254 goto cleanup;
1255 }
1256 if (alloc->resource_owner != alloc0->resource_owner) {
1257 fail_reason = 2;
1258 goto cleanup;
1259 }
1260 if (alloc->resource_owner) {
1261 if (alloc->owner.resource != alloc0->owner.resource) {
1262 fail_reason = 3;
1263 goto cleanup;
1264 }
1265 if (alloc->owner.resource->device != device) {
1266 fail_reason = 4;
1267 goto cleanup;
1268 }
1269 if (alloc->owner.resource->shared_owner) {
1270 fail_reason = 5;
1271 goto cleanup;
1272 }
1273 } else {
1274 if (alloc->owner.device != device) {
1275 fail_reason = 6;
1276 goto cleanup;
1277 }
1278 }
1279 return 0;
1280 cleanup:
1281 pr_err("Alloc validation failed: reason: %d %x",
1282 fail_reason, alloc_handle.v);
1283 return -EINVAL;
1284 }
1285
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v1 4/9] drivers: hv: dxgkrnl: Implement operations with GPU sync objects
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
2022-01-12 19:55 ` [PATCH v1 2/9] drivers: hv: dxgkrnl: Open device object, adapter enumeration, dxgdevice, dxgcontext creation Iouri Tarassov
2022-01-12 19:55 ` [PATCH v1 3/9] drivers: hv: dxgkrnl: Implement creation/destruction of GPU allocations/resources Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-12 19:55 ` [PATCH v1 5/9] drivers: hv: dxgkrnl: Implement sharing resources and " Iouri Tarassov
` (6 subsequent siblings)
9 siblings, 0 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
Implement ioctls for using GPU synchronization objects:
LX_DXCREATESYNCHRONIZATIONOBJECT,
LX_DXSIGNALSYNCHRONIZATIONOBJECT,
LX_DXWAITFORSYNCHRONIZATIONOBJECT,
LX_DXDESTROYSYNCHRONIZATIONOBJECT,
LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU,
LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU,
LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2,
LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU,
LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU.
GPU synchronization objects are used to synchornize GPU command
execution between different execution contexts. A wait for a sync
object could be submitted to a GPU context (thread) or could be
done on CPU. The wait is satisfied when the sync object is signaled.
The signal operation could be submitted to a GPU context (thread) or
could be signaled by a CPU thread.
The driver creates the corresponsing tracking structures and sends
VM bus messages to the host to do the corresponding operation.
When a caller needs to wait for a sync object on CPU, an event structure
is added to the global list (dxgglobal->host_event_list_head). Each
list entry has an ID and a pointer to the event to signal. When the sync
object is signaled on the host, the host sends a message to the guest
with the event ID to signal. dxgglobal_signal_host_event() processes this
message and signals the corresponding CPU event.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 280 ++++++++++-
drivers/hv/dxgkrnl/dxgkrnl.h | 4 +-
drivers/hv/dxgkrnl/dxgvmbus.c | 429 +++++++++++++++-
drivers/hv/dxgkrnl/ioctl.c | 840 ++++++++++++++++++++++++++++++++
4 files changed, 1541 insertions(+), 12 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index 26648f7fe36f..da6d7c4a7dc5 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -167,6 +167,55 @@ void dxgadapter_remove_process(struct dxgprocess_adapter *process_info)
process_info->adapter_process_list_entry.prev = NULL;
}
+void dxgadapter_remove_shared_resource(struct dxgadapter *adapter,
+ struct dxgsharedresource *object)
+{
+ down_write(&adapter->shared_resource_list_lock);
+ if (object->shared_resource_list_entry.next) {
+ list_del(&object->shared_resource_list_entry);
+ object->shared_resource_list_entry.next = NULL;
+ }
+ up_write(&adapter->shared_resource_list_lock);
+}
+
+void dxgadapter_add_shared_syncobj(struct dxgadapter *adapter,
+ struct dxgsharedsyncobject *object)
+{
+ down_write(&adapter->shared_resource_list_lock);
+ list_add_tail(&object->adapter_shared_syncobj_list_entry,
+ &adapter->adapter_shared_syncobj_list_head);
+ up_write(&adapter->shared_resource_list_lock);
+}
+
+void dxgadapter_remove_shared_syncobj(struct dxgadapter *adapter,
+ struct dxgsharedsyncobject *object)
+{
+ down_write(&adapter->shared_resource_list_lock);
+ if (object->adapter_shared_syncobj_list_entry.next) {
+ list_del(&object->adapter_shared_syncobj_list_entry);
+ object->adapter_shared_syncobj_list_entry.next = NULL;
+ }
+ up_write(&adapter->shared_resource_list_lock);
+}
+
+void dxgadapter_add_syncobj(struct dxgadapter *adapter,
+ struct dxgsyncobject *object)
+{
+ down_write(&adapter->shared_resource_list_lock);
+ list_add_tail(&object->syncobj_list_entry, &adapter->syncobj_list_head);
+ up_write(&adapter->shared_resource_list_lock);
+}
+
+void dxgadapter_remove_syncobj(struct dxgsyncobject *object)
+{
+ down_write(&object->adapter->shared_resource_list_lock);
+ if (object->syncobj_list_entry.next) {
+ list_del(&object->syncobj_list_entry);
+ object->syncobj_list_entry.next = NULL;
+ }
+ up_write(&object->adapter->shared_resource_list_lock);
+}
+
int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter)
{
down_write(&adapter->core_lock);
@@ -679,6 +728,30 @@ void dxgdevice_release(struct kref *refcount)
vfree(device);
}
+void dxgdevice_add_syncobj(struct dxgdevice *device,
+ struct dxgsyncobject *syncobj)
+{
+ dxgdevice_acquire_alloc_list_lock(device);
+ list_add_tail(&syncobj->syncobj_list_entry, &device->syncobj_list_head);
+ kref_get(&syncobj->syncobj_kref);
+ dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_syncobj(struct dxgsyncobject *entry)
+{
+ struct dxgdevice *device = entry->device;
+
+ dxgdevice_acquire_alloc_list_lock(device);
+ if (entry->syncobj_list_entry.next) {
+ list_del(&entry->syncobj_list_entry);
+ entry->syncobj_list_entry.next = NULL;
+ kref_put(&entry->syncobj_kref, dxgsyncobject_release);
+ }
+ dxgdevice_release_alloc_list_lock(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ entry->device = NULL;
+}
+
struct dxgcontext *dxgcontext_create(struct dxgdevice *device)
{
struct dxgcontext *context = vzalloc(sizeof(struct dxgcontext));
@@ -935,28 +1008,221 @@ void dxgprocess_adapter_remove_device(struct dxgdevice *device)
mutex_unlock(&device->adapter_info->device_list_mutex);
}
-void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwqueue)
+struct dxgsharedsyncobject *dxgsharedsyncobj_create(struct dxgadapter *adapter,
+ struct dxgsyncobject *so)
{
- /* Placeholder */
+ struct dxgsharedsyncobject *syncobj;
+
+ syncobj = vzalloc(sizeof(*syncobj));
+ if (syncobj) {
+ kref_init(&syncobj->ssyncobj_kref);
+ INIT_LIST_HEAD(&syncobj->shared_syncobj_list_head);
+ syncobj->adapter = adapter;
+ syncobj->type = so->type;
+ syncobj->monitored_fence = so->monitored_fence;
+ dxgadapter_add_shared_syncobj(adapter, syncobj);
+ kref_get(&adapter->adapter_kref);
+ init_rwsem(&syncobj->syncobj_list_lock);
+ mutex_init(&syncobj->fd_mutex);
+ }
+ return syncobj;
}
-void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue)
+void dxgsharedsyncobj_release(struct kref *refcount)
{
- /* Placeholder */
+ struct dxgsharedsyncobject *syncobj;
+
+ syncobj = container_of(refcount, struct dxgsharedsyncobject,
+ ssyncobj_kref);
+ dev_dbg(dxgglobaldev, "Destroying shared sync object %p", syncobj);
+ if (syncobj->adapter) {
+ dxgadapter_remove_shared_syncobj(syncobj->adapter,
+ syncobj);
+ kref_put(&syncobj->adapter->adapter_kref,
+ dxgadapter_release);
+ }
+ vfree(syncobj);
}
-void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue)
+void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *shared,
+ struct dxgsyncobject *syncobj)
{
- /* Placeholder */
+ dev_dbg(dxgglobaldev, "%s 0x%p 0x%p", __func__, shared, syncobj);
+ kref_get(&shared->ssyncobj_kref);
+ down_write(&shared->syncobj_list_lock);
+ list_add(&syncobj->shared_syncobj_list_entry,
+ &shared->shared_syncobj_list_head);
+ syncobj->shared_owner = shared;
+ up_write(&shared->syncobj_list_lock);
+}
+
+void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *shared,
+ struct dxgsyncobject *syncobj)
+{
+ dev_dbg(dxgglobaldev, "%s 0x%p", __func__, shared);
+ down_write(&shared->syncobj_list_lock);
+ list_del(&syncobj->shared_syncobj_list_entry);
+ up_write(&shared->syncobj_list_lock);
+}
+
+struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
+ struct dxgdevice *device,
+ struct dxgadapter *adapter,
+ enum
+ d3dddi_synchronizationobject_type
+ type,
+ struct
+ d3dddi_synchronizationobject_flags
+ flags)
+{
+ struct dxgsyncobject *syncobj;
+
+ syncobj = vzalloc(sizeof(*syncobj));
+ if (syncobj == NULL)
+ goto cleanup;
+ syncobj->type = type;
+ syncobj->process = process;
+ switch (type) {
+ case _D3DDDI_MONITORED_FENCE:
+ case _D3DDDI_PERIODIC_MONITORED_FENCE:
+ syncobj->monitored_fence = 1;
+ break;
+ case _D3DDDI_CPU_NOTIFICATION:
+ syncobj->cpu_event = 1;
+ syncobj->host_event = vzalloc(sizeof(struct dxghostevent));
+ if (syncobj->host_event == NULL)
+ goto cleanup;
+ break;
+ default:
+ break;
+ }
+ if (flags.shared) {
+ syncobj->shared = 1;
+ if (!flags.nt_security_sharing) {
+ dev_err(dxgglobaldev,
+ "%s: nt_security_sharing must be set",
+ __func__);
+ goto cleanup;
+ }
+ }
+
+ kref_init(&syncobj->syncobj_kref);
+
+ if (syncobj->monitored_fence) {
+ syncobj->device = device;
+ syncobj->device_handle = device->handle;
+ kref_get(&device->device_kref);
+ dxgdevice_add_syncobj(device, syncobj);
+ } else {
+ dxgadapter_add_syncobj(adapter, syncobj);
+ }
+ syncobj->adapter = adapter;
+ kref_get(&adapter->adapter_kref);
+
+ dev_dbg(dxgglobaldev, "%s 0x%p\n", __func__, syncobj);
+ return syncobj;
+cleanup:
+ if (syncobj->host_event)
+ vfree(syncobj->host_event);
+ if (syncobj)
+ vfree(syncobj);
+ return NULL;
}
void dxgsyncobject_destroy(struct dxgprocess *process,
struct dxgsyncobject *syncobj)
{
- /* Placeholder */
+ int destroyed;
+ struct dxghosteventcpu *host_event;
+
+ dev_dbg(dxgglobaldev, "%s 0x%p", __func__, syncobj);
+
+ dxgsyncobject_stop(syncobj);
+
+ destroyed = test_and_set_bit(0, &syncobj->flags);
+ if (!destroyed) {
+ dev_dbg(dxgglobaldev, "Deleting handle: %x", syncobj->handle.v);
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ if (syncobj->handle.v) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGSYNCOBJECT,
+ syncobj->handle);
+ syncobj->handle.v = 0;
+ kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
+ }
+ 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
+ dxgadapter_remove_syncobj(syncobj);
+ if (syncobj->adapter) {
+ kref_put(&syncobj->adapter->adapter_kref,
+ dxgadapter_release);
+ syncobj->adapter = NULL;
+ }
+ }
+ kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
}
void dxgsyncobject_stop(struct dxgsyncobject *syncobj)
+{
+ int stopped = test_and_set_bit(1, &syncobj->flags);
+
+ if (!stopped) {
+ dev_dbg(dxgglobaldev, "stopping");
+ if (syncobj->monitored_fence) {
+ if (syncobj->mapped_address) {
+ int ret =
+ dxg_unmap_iospace(syncobj->mapped_address,
+ PAGE_SIZE);
+
+ (void)ret;
+ dev_dbg(dxgglobaldev, "fence is unmapped %d %p\n",
+ ret, syncobj->mapped_address);
+ syncobj->mapped_address = NULL;
+ }
+ }
+ }
+}
+
+void dxgsyncobject_release(struct kref *refcount)
+{
+ struct dxgsyncobject *syncobj;
+
+ syncobj = container_of(refcount, struct dxgsyncobject, syncobj_kref);
+ if (syncobj->shared_owner) {
+ dxgsharedsyncobj_remove_syncobj(syncobj->shared_owner,
+ syncobj);
+ kref_put(&syncobj->shared_owner->ssyncobj_kref,
+ dxgsharedsyncobj_release);
+ }
+ if (syncobj->host_event)
+ vfree(syncobj->host_event);
+ vfree(syncobj);
+}
+
+void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwqueue)
+{
+ /* Placeholder */
+}
+
+void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue)
+{
+ /* Placeholder */
+}
+
+void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue)
{
/* Placeholder */
}
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 269391319f56..9d2d55d9b509 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -100,8 +100,8 @@ struct dxgpagingqueue {
* a message from host.
*/
enum dxghosteventtype {
- dxghostevent_cpu_event,
- dxghostevent_dma_fence
+ dxghostevent_cpu_event = 1,
+ dxghostevent_dma_fence = 2
};
struct dxghostevent {
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index aba5f1cef431..4fe799eb8968 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -251,18 +251,66 @@ static inline void command_vm_to_host_init1(struct dxgkvmb_command_vm_to_host
command->channel_type = DXGKVMB_VM_TO_HOST;
}
+void set_guest_data(struct dxgkvmb_command_host_to_vm *packet,
+ u32 packet_length)
+{
+ struct dxgkvmb_command_setguestdata *command = (void *)packet;
+
+ dev_dbg(dxgglobaldev, "%s: %d %d %p %p", __func__,
+ command->data_type,
+ command->data32,
+ command->guest_pointer,
+ &dxgglobal->device_state_counter);
+ if (command->data_type == SETGUESTDATA_DATATYPE_DWORD &&
+ command->guest_pointer == &dxgglobal->device_state_counter &&
+ command->data32 != 0) {
+ atomic_inc(&dxgglobal->device_state_counter);
+ }
+}
+
+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)) {
+ pr_err("invalid packet size");
+ return;
+ }
+ if (command->event == 0) {
+ pr_err("invalid event pointer");
+ return;
+ }
+ dxgglobal_signal_host_event(command->event);
+}
+
void process_inband_packet(struct dxgvmbuschannel *channel,
struct vmpacket_descriptor *desc)
{
u32 packet_length = hv_pkt_datalen(desc);
+ struct dxgkvmb_command_host_to_vm *packet;
if (channel->adapter == NULL) {
if (packet_length < sizeof(struct dxgkvmb_command_host_to_vm)) {
pr_err("Invalid global packet");
} else {
- /*
- *Placeholder
- */
+ packet = hv_pkt_data(desc);
+ dev_dbg(dxgglobaldev, "global packet %d",
+ packet->command_type);
+ switch (packet->command_type) {
+ case DXGK_VMBCOMMAND_SETGUESTDATA:
+ set_guest_data(packet, packet_length);
+ break;
+ case DXGK_VMBCOMMAND_SIGNALGUESTEVENT:
+ case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE:
+ signal_guest_event(packet, packet_length);
+ break;
+ case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION:
+ break;
+ default:
+ pr_err("unexpected host message %d",
+ packet->command_type);
+ }
}
} else {
pr_err("Unexpected packet for adapter channel");
@@ -444,6 +492,18 @@ dxgvmb_send_sync_msg_ntstatus(struct dxgvmbuschannel *channel,
return ret;
}
+static int check_iospace_address(unsigned long address, u32 size)
+{
+ if (address < dxgglobal->mmiospace_base ||
+ size > dxgglobal->mmiospace_size ||
+ address >= (dxgglobal->mmiospace_base +
+ dxgglobal->mmiospace_size - size)) {
+ pr_err("invalid iospace address %lx", address);
+ return -EINVAL;
+ }
+ return 0;
+}
+
int dxg_unmap_iospace(void *va, u32 size)
{
int ret = 0;
@@ -464,6 +524,54 @@ int dxg_unmap_iospace(void *va, u32 size)
return 0;
}
+static u8 *dxg_map_iospace(u64 iospace_address, u32 size,
+ unsigned long protection, bool cached)
+{
+ struct vm_area_struct *vma;
+ unsigned long va;
+ int ret = 0;
+
+ dev_dbg(dxgglobaldev, "%s: %llx %x %lx",
+ __func__, iospace_address, size, protection);
+ if (check_iospace_address(iospace_address, size) < 0) {
+ pr_err("%s: invalid address", __func__);
+ return NULL;
+ }
+
+ va = vm_mmap(NULL, 0, size, protection, MAP_SHARED | MAP_ANONYMOUS, 0);
+ if ((long)va <= 0) {
+ pr_err("vm_mmap failed %lx %d", va, size);
+ return NULL;
+ }
+
+ mmap_read_lock(current->mm);
+ vma = find_vma(current->mm, (unsigned long)va);
+ if (vma) {
+ pgprot_t prot = vma->vm_page_prot;
+
+ if (!cached)
+ prot = pgprot_writecombine(prot);
+ dev_dbg(dxgglobaldev, "vma: %lx %lx %lx",
+ vma->vm_start, vma->vm_end, va);
+ vma->vm_pgoff = iospace_address >> PAGE_SHIFT;
+ ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ size, prot);
+ if (ret)
+ pr_err("io_remap_pfn_range failed: %d", ret);
+ } else {
+ pr_err("failed to find vma: %p %lx", vma, va);
+ ret = -ENOMEM;
+ }
+ mmap_read_unlock(current->mm);
+
+ if (ret) {
+ dxg_unmap_iospace((void *)va, size);
+ return NULL;
+ }
+ dev_dbg(dxgglobaldev, "%s end: %lx", __func__, va);
+ return (u8 *) va;
+}
+
/*
* Global messages to the host
*/
@@ -582,6 +690,39 @@ int dxgvmb_send_destroy_process(struct d3dkmthandle process)
return ret;
}
+int dxgvmb_send_destroy_sync_object(struct dxgprocess *process,
+ struct d3dkmthandle sync_object)
+{
+ struct dxgkvmb_command_destroysyncobject *command;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, NULL, process, sizeof(*command));
+ if (ret)
+ return ret;
+ command = (void *)msg.msg;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+
+ command_vm_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_DESTROYSYNCOBJECT,
+ process->host_handle);
+ command->sync_object = sync_object;
+
+ ret = dxgvmb_send_sync_msg_ntstatus(dxgglobal_get_dxgvmbuschannel(),
+ msg.hdr, msg.size);
+
+ dxgglobal_release_channel_lock();
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
/*
* Virtual GPU messages to the host
*/
@@ -1439,6 +1580,288 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
return ret;
}
+static void set_result(struct d3dkmt_createsynchronizationobject2 *args,
+ u64 fence_gpu_va, u8 *va)
+{
+ args->info.periodic_monitored_fence.fence_gpu_virtual_address =
+ fence_gpu_va;
+ args->info.periodic_monitored_fence.fence_cpu_virtual_address = va;
+}
+
+int
+dxgvmb_send_create_sync_object(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_createsynchronizationobject2 *args,
+ struct dxgsyncobject *syncobj)
+{
+ struct dxgkvmb_command_createsyncobject_return result = { };
+ struct dxgkvmb_command_createsyncobject *command;
+ int ret;
+ u8 *va = 0;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_CREATESYNCOBJECT,
+ process->host_handle);
+ command->args = *args;
+ command->client_hint = 1; /* CLIENTHINT_UMD */
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result,
+ sizeof(result));
+ if (ret < 0) {
+ pr_err("%s failed %d", __func__, ret);
+ goto cleanup;
+ }
+ args->sync_object = result.sync_object;
+ if (syncobj->shared) {
+ if (result.global_sync_object.v == 0) {
+ pr_err("shared handle is 0");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ args->info.shared_handle = result.global_sync_object;
+ }
+
+ if (syncobj->monitored_fence) {
+ va = dxg_map_iospace(result.fence_storage_address, PAGE_SIZE,
+ PROT_READ | PROT_WRITE, true);
+ if (va == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ if (args->info.type == _D3DDDI_MONITORED_FENCE) {
+ args->info.monitored_fence.fence_gpu_virtual_address =
+ result.fence_gpu_va;
+ args->info.monitored_fence.fence_cpu_virtual_address =
+ va;
+ {
+ unsigned long value;
+
+ dev_dbg(dxgglobaldev, "fence cpu va: %p", va);
+ ret = copy_from_user(&value, va,
+ sizeof(u64));
+ if (ret) {
+ pr_err("failed to read fence");
+ ret = -EINVAL;
+ } else {
+ dev_dbg(dxgglobaldev, "fence value:%lx",
+ value);
+ }
+ }
+ } else {
+ set_result(args, result.fence_gpu_va, va);
+ }
+ syncobj->mapped_address = va;
+ }
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ 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};
+
+ 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) {
+ pr_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) {
+ pr_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) {
+ pr_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)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, 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) {
+ pr_err("%s failed to copy objects", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ current_pos += object_size;
+ ret = copy_from_user(current_pos, args->fence_values, fence_size);
+ if (ret) {
+ pr_err("%s failed to copy fences", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, 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};
+
+ 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)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, 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/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 79dc22379ec4..f484b0da702c 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -1473,6 +1473,828 @@ dxgk_destroy_allocation(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgk_create_sync_object(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ 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 dxgsharedsyncobject *syncobjgbl = NULL;
+ struct dxghosteventcpu *host_event = NULL;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0)
+ goto cleanup;
+
+ device_lock_acquired = true;
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ syncobj = dxgsyncobject_create(process, device, adapter, args.info.type,
+ args.info.flags);
+ if (syncobj == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.info.type == _D3DDDI_CPU_NOTIFICATION) {
+ event = eventfd_ctx_fdget((int)
+ args.info.cpu_notification.event);
+ if (IS_ERR(event)) {
+ pr_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;
+ dev_dbg(dxgglobaldev, "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;
+
+ if (args.info.flags.shared) {
+ if (args.info.shared_handle.v == 0) {
+ pr_err("shared handle should not be 0");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ syncobjgbl = dxgsharedsyncobj_create(device->adapter, syncobj);
+ if (syncobjgbl == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ dxgsharedsyncobj_add_syncobj(syncobjgbl, syncobj);
+
+ syncobjgbl->host_shared_handle = args.info.shared_handle;
+ }
+
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy output args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(&process->handle_table, syncobj,
+ HMGRENTRY_TYPE_DXGSYNCOBJECT,
+ args.sync_object);
+ if (ret >= 0)
+ syncobj->handle = args.sync_object;
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+cleanup:
+
+ if (ret < 0) {
+ if (syncobj) {
+ dxgsyncobject_destroy(process, syncobj);
+ if (args.sync_object.v)
+ dxgvmb_send_destroy_sync_object(process,
+ args.sync_object);
+ event = NULL;
+ }
+ if (event)
+ eventfd_ctx_put(event);
+ }
+ if (syncobjgbl)
+ kref_put(&syncobjgbl->ssyncobj_kref, dxgsharedsyncobj_release);
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device_lock_acquired)
+ dxgdevice_release_lock_shared(device);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_destroy_sync_object(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_destroysynchronizationobject args;
+ struct dxgsyncobject *syncobj = NULL;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dev_dbg(dxgglobaldev, "handle 0x%x", args.sync_object.v);
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ syncobj = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGSYNCOBJECT,
+ args.sync_object);
+ if (syncobj) {
+ dev_dbg(dxgglobaldev, "syncobj 0x%p", syncobj);
+ syncobj->handle.v = 0;
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGSYNCOBJECT,
+ args.sync_object);
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (syncobj == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dxgsyncobject_destroy(process, syncobj);
+
+ ret = dxgvmb_send_destroy_sync_object(process, args.sync_object);
+
+cleanup:
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_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;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ 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 = vzalloc(sizeof(*host_event));
+ 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)) {
+ pr_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;
+ vfree(host_event);
+ host_event = NULL;
+ }
+ }
+ if (event)
+ eventfd_ctx_put(event);
+ if (host_event)
+ vfree(host_event);
+ }
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_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) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (args.object_count == 0 ||
+ args.object_count > D3DDDI_MAX_OBJECT_SIGNALED) {
+ dev_dbg(dxgglobaldev, "Too many objects: %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);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_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) {
+ pr_err("%s failed to copy input args", __func__);
+ 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);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_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) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.flags.enqueue_cpu_event) {
+ if (args.object_count != 0 || args.cpu_event_handle == 0) {
+ pr_err("Bad input for 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) {
+ pr_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) {
+ pr_err("%s failed to copy context handle", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.flags.enqueue_cpu_event) {
+ host_event = vzalloc(sizeof(*host_event));
+ 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)) {
+ pr_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;
+ vfree(host_event);
+ host_event = NULL;
+ }
+ }
+ if (event)
+ eventfd_ctx_put(event);
+ if (host_event)
+ vfree(host_event);
+ }
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_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) {
+ pr_err("%s failed to copy input args", __func__);
+ 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;
+ }
+
+ dev_dbg(dxgglobaldev, "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);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_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) {
+ pr_err("%s failed to copy input args", __func__);
+ 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 = vzalloc(sizeof(*async_host_event));
+ 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)) {
+ pr_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_killable(&local_event);
+ if (ret)
+ pr_err("%s: wait_for_completion_killable failed: %d",
+ __func__, ret);
+ }
+
+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;
+ vfree(async_host_event);
+ async_host_event = NULL;
+ } else {
+ pr_err("Invalid event type");
+ DXGKRNL_ASSERT(0);
+ }
+ }
+ }
+ if (event)
+ eventfd_ctx_put(event);
+ if (async_host_event)
+ vfree(async_host_event);
+ }
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_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) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE ||
+ args.object_count == 0) {
+ pr_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) {
+ pr_err("%s failed to copy objects", __func__);
+ 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) {
+ pr_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) {
+ pr_err("Invalid syncobj: %x", objects[0].v);
+ ret = -EINVAL;
+ } else {
+ monitored_fence = syncobj->monitored_fence;
+ }
+ } else {
+ pr_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) {
+ pr_err("%s failed to copy fences", __func__);
+ 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);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
static int
dxgk_render(struct dxgprocess *process, void *__user inargs)
{
@@ -1565,6 +2387,12 @@ void init_ioctls(void)
LX_DXCREATEALLOCATION);
SET_IOCTL(/*0x9 */ dxgk_query_adapter_info,
LX_DXQUERYADAPTERINFO);
+ SET_IOCTL(/*0x10 */ dxgk_create_sync_object,
+ LX_DXCREATESYNCHRONIZATIONOBJECT);
+ SET_IOCTL(/*0x11 */ dxgk_signal_sync_object,
+ LX_DXSIGNALSYNCHRONIZATIONOBJECT);
+ SET_IOCTL(/*0x12 */ dxgk_wait_sync_object,
+ LX_DXWAITFORSYNCHRONIZATIONOBJECT);
SET_IOCTL(/*0x13 */ dxgk_destroy_allocation,
LX_DXDESTROYALLOCATION2);
SET_IOCTL(/*0x14 */ dxgk_enum_adapters,
@@ -1577,10 +2405,22 @@ void init_ioctls(void)
LX_DXDESTROYDEVICE);
SET_IOCTL(/*0x1a */ dxgk_destroy_hwcontext,
LX_DXDESTROYHWCONTEXT);
+ SET_IOCTL(/*0x1d */ dxgk_destroy_sync_object,
+ LX_DXDESTROYSYNCHRONIZATIONOBJECT);
SET_IOCTL(/*0x23 */ dxgk_get_shared_resource_adapter_luid,
LX_DXGETSHAREDRESOURCEADAPTERLUID);
SET_IOCTL(/*0x2d */ dxgk_render,
LX_DXRENDER);
+ SET_IOCTL(/*0x31 */ dxgk_signal_sync_object_cpu,
+ LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU);
+ SET_IOCTL(/*0x32 */ dxgk_signal_sync_object_gpu,
+ LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU);
+ SET_IOCTL(/*0x33 */ dxgk_signal_sync_object_gpu2,
+ LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2);
+ SET_IOCTL(/*0x3a */ dxgk_wait_sync_object_cpu,
+ LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU);
+ SET_IOCTL(/*0x3b */ dxgk_wait_sync_object_gpu,
+ LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU);
SET_IOCTL(/*0x3e */ dxgk_enum_adapters3,
LX_DXENUMADAPTERS3);
}
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* [PATCH v1 5/9] drivers: hv: dxgkrnl: Implement sharing resources and sync objects
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
` (2 preceding siblings ...)
2022-01-12 19:55 ` [PATCH v1 4/9] drivers: hv: dxgkrnl: Implement operations with GPU sync objects Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-12 19:55 ` [PATCH v1 6/9] drivers: hv: dxgkrnl: Seal the shared resource object when dxgk_share_objects is called Iouri Tarassov
` (5 subsequent siblings)
9 siblings, 0 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
Implement IOCTLs for sharing dxgresource and dxgsyncobject objects between
processes in the virtual machine.
Resources and sync objects are shared using FD (file descriptor) handles.
The name "NT handle" is used to be compatible with Windows implementation.
An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The given FD
handle could be sent to another process using any Linux API.
To use a shared object in WDDM API calls, the object needs to be opened
using its FD handle. An object could be opened by the following ioctls:
LX_DXOPENRESOURCEFROMNTHANDLE,
LX_DXOPENSYNCOBJECTFROMNTHANDLE2.
LX_DXQUERYRESOURCEINFOFROMNTHANDLE is used to query private driver
data of a shared resource object. This private data needs to be used
to actually open the object using LX_DXOPENRESOURCEFROMNTHANDLE.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgvmbus.c | 190 +++++++
drivers/hv/dxgkrnl/ioctl.c | 936 +++++++++++++++++++++++++++++++++-
2 files changed, 1123 insertions(+), 3 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 4fe799eb8968..6fc0771f383d 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -690,6 +690,142 @@ int dxgvmb_send_destroy_process(struct d3dkmthandle process)
return ret;
}
+int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process,
+ struct dxgvmbuschannel *channel,
+ struct d3dkmt_opensyncobjectfromnthandle2
+ *args,
+ struct dxgsyncobject *syncobj)
+{
+ struct dxgkvmb_command_opensyncobject *command;
+ struct dxgkvmb_command_opensyncobject_return result = { };
+ int ret;
+ struct dxgvmbusmsg msg;
+
+ ret = init_message(&msg, NULL, process, sizeof(*command));
+ if (ret)
+ return ret;
+ command = (void *)msg.msg;
+
+ command_vm_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_OPENSYNCOBJECT,
+ process->host_handle);
+ command->device = args->device;
+ command->global_sync_object = syncobj->shared_owner->host_shared_handle;
+ command->flags = args->flags;
+ if (syncobj->monitored_fence)
+ command->engine_affinity =
+ args->monitored_fence.engine_affinity;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+
+ ret = dxgvmb_send_sync_msg(channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+
+ dxgglobal_release_channel_lock();
+
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(result.status);
+ if (ret < 0)
+ goto cleanup;
+
+ args->sync_object = result.sync_object;
+ if (syncobj->monitored_fence) {
+ void *va = dxg_map_iospace(result.guest_cpu_physical_address,
+ PAGE_SIZE, PROT_READ | PROT_WRITE,
+ true);
+ if (va == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ args->monitored_fence.fence_value_cpu_va = va;
+ args->monitored_fence.fence_value_gpu_va =
+ result.gpu_virtual_address;
+ syncobj->mapped_address = va;
+ }
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process,
+ struct d3dkmthandle object,
+ struct d3dkmthandle *shared_handle)
+{
+ struct dxgkvmb_command_createntsharedobject *command;
+ int ret;
+ struct dxgvmbusmsg msg;
+
+ ret = init_message(&msg, NULL, process, sizeof(*command));
+ if (ret)
+ return ret;
+ command = (void *)msg.msg;
+
+ command_vm_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_CREATENTSHAREDOBJECT,
+ process->host_handle);
+ command->object = object;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+
+ ret = dxgvmb_send_sync_msg(dxgglobal_get_dxgvmbuschannel(),
+ msg.hdr, msg.size, shared_handle,
+ sizeof(*shared_handle));
+
+ dxgglobal_release_channel_lock();
+
+ if (ret < 0)
+ goto cleanup;
+ if (shared_handle->v == 0) {
+ pr_err("failed to create NT shared object");
+ ret = -ENOTRECOVERABLE;
+ }
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_destroy_nt_shared_object(struct d3dkmthandle shared_handle)
+{
+ struct dxgkvmb_command_destroyntsharedobject *command;
+ int ret;
+ struct dxgvmbusmsg msg;
+
+ ret = init_message(&msg, NULL, NULL, sizeof(*command));
+ if (ret)
+ return ret;
+ command = (void *)msg.msg;
+
+ command_vm_to_host_init1(&command->hdr,
+ DXGK_VMBCOMMAND_DESTROYNTSHAREDOBJECT);
+ command->shared_handle = shared_handle;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+
+ ret = dxgvmb_send_sync_msg_ntstatus(dxgglobal_get_dxgvmbuschannel(),
+ msg.hdr, msg.size);
+
+ dxgglobal_release_channel_lock();
+
+cleanup:
+ free_message(&msg, NULL);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
int dxgvmb_send_destroy_sync_object(struct dxgprocess *process,
struct d3dkmthandle sync_object)
{
@@ -1495,6 +1631,60 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_open_resource(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle device,
+ struct d3dkmthandle global_share,
+ u32 allocation_count,
+ u32 total_priv_drv_data_size,
+ struct d3dkmthandle *resource_handle,
+ struct d3dkmthandle *alloc_handles)
+{
+ struct dxgkvmb_command_openresource *command;
+ struct dxgkvmb_command_openresource_return *result;
+ struct d3dkmthandle *handles;
+ int ret;
+ int i;
+ u32 result_size = allocation_count * sizeof(struct d3dkmthandle) +
+ sizeof(*result);
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
+
+ ret = init_message_res(&msg, adapter, process, sizeof(*command),
+ result_size);
+ if (ret)
+ goto cleanup;
+ command = msg.msg;
+ result = msg.res;
+
+ command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_OPENRESOURCE,
+ process->host_handle);
+ command->device = device;
+ command->nt_security_sharing = 1;
+ command->global_share = global_share;
+ command->allocation_count = allocation_count;
+ command->total_priv_drv_data_size = total_priv_drv_data_size;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ result, msg.res_size);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(result->status);
+ if (ret < 0)
+ goto cleanup;
+
+ *resource_handle = result->resource;
+ handles = (struct d3dkmthandle *) &result[1];
+ for (i = 0; i < allocation_count; i++)
+ alloc_handles[i] = handles[i];
+
+cleanup:
+ free_message((struct dxgvmbusmsg *)&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
enum d3dkmdt_standardallocationtype alloctype,
struct d3dkmdt_gdisurfacedata *alloc_data,
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index f484b0da702c..2086f7347ba3 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -37,6 +37,61 @@ static char *errorstr(int ret)
return ret < 0 ? "err" : "";
}
+static int dxgsyncobj_release(struct inode *inode, struct file *file)
+{
+ struct dxgsharedsyncobject *syncobj = file->private_data;
+
+ dev_dbg(dxgglobaldev, "%s: %p", __func__, syncobj);
+ mutex_lock(&syncobj->fd_mutex);
+ kref_get(&syncobj->ssyncobj_kref);
+ syncobj->host_shared_handle_nt_reference--;
+ if (syncobj->host_shared_handle_nt_reference == 0) {
+ if (syncobj->host_shared_handle_nt.v) {
+ dxgvmb_send_destroy_nt_shared_object(
+ syncobj->host_shared_handle_nt);
+ dev_dbg(dxgglobaldev, "Syncobj host_handle_nt destroyed: %x",
+ syncobj->host_shared_handle_nt.v);
+ syncobj->host_shared_handle_nt.v = 0;
+ }
+ kref_put(&syncobj->ssyncobj_kref, dxgsharedsyncobj_release);
+ }
+ mutex_unlock(&syncobj->fd_mutex);
+ kref_put(&syncobj->ssyncobj_kref, dxgsharedsyncobj_release);
+ return 0;
+}
+
+static const struct file_operations dxg_syncobj_fops = {
+ .release = dxgsyncobj_release,
+};
+
+static int dxgsharedresource_release(struct inode *inode, struct file *file)
+{
+ struct dxgsharedresource *resource = file->private_data;
+
+ dev_dbg(dxgglobaldev, "%s: %p", __func__, resource);
+ mutex_lock(&resource->fd_mutex);
+ kref_get(&resource->sresource_kref);
+ resource->host_shared_handle_nt_reference--;
+ if (resource->host_shared_handle_nt_reference == 0) {
+ if (resource->host_shared_handle_nt.v) {
+ dxgvmb_send_destroy_nt_shared_object(
+ resource->host_shared_handle_nt);
+ dev_dbg(dxgglobaldev,
+ "Resource host_handle_nt destroyed: %x",
+ resource->host_shared_handle_nt.v);
+ resource->host_shared_handle_nt.v = 0;
+ }
+ kref_put(&resource->sresource_kref, dxgsharedresource_destroy);
+ }
+ mutex_unlock(&resource->fd_mutex);
+ kref_put(&resource->sresource_kref, dxgsharedresource_destroy);
+ return 0;
+}
+
+static const struct file_operations dxg_resource_fops = {
+ .release = dxgsharedresource_release,
+};
+
static int dxgk_open_adapter_from_luid(struct dxgprocess *process,
void *__user inargs)
{
@@ -219,6 +274,97 @@ dxgkp_enum_adapters(struct dxgprocess *process,
return ret;
}
+static int dxgsharedresource_seal(struct dxgsharedresource *shared_resource)
+{
+ int ret = 0;
+ int i = 0;
+ u8 *private_data;
+ u32 data_size;
+ struct dxgresource *resource;
+ struct dxgallocation *alloc;
+
+ dev_dbg(dxgglobaldev, "Sealing resource: %p", shared_resource);
+
+ down_write(&shared_resource->adapter->shared_resource_list_lock);
+ if (shared_resource->sealed) {
+ dev_dbg(dxgglobaldev, "Resource already sealed");
+ goto cleanup;
+ }
+ shared_resource->sealed = 1;
+ if (!list_empty(&shared_resource->resource_list_head)) {
+ resource =
+ list_first_entry(&shared_resource->resource_list_head,
+ struct dxgresource,
+ shared_resource_list_entry);
+ dev_dbg(dxgglobaldev, "First resource: %p", resource);
+ mutex_lock(&resource->resource_mutex);
+ list_for_each_entry(alloc, &resource->alloc_list_head,
+ alloc_list_entry) {
+ dev_dbg(dxgglobaldev, "Resource alloc: %p %d", alloc,
+ alloc->priv_drv_data->data_size);
+ shared_resource->allocation_count++;
+ shared_resource->alloc_private_data_size +=
+ alloc->priv_drv_data->data_size;
+ if (shared_resource->alloc_private_data_size <
+ alloc->priv_drv_data->data_size) {
+ pr_err("alloc private data overflow");
+ ret = -EINVAL;
+ goto cleanup1;
+ }
+ }
+ if (shared_resource->alloc_private_data_size == 0) {
+ ret = -EINVAL;
+ goto cleanup1;
+ }
+ shared_resource->alloc_private_data =
+ vzalloc(shared_resource->alloc_private_data_size);
+ if (shared_resource->alloc_private_data == NULL) {
+ ret = -EINVAL;
+ goto cleanup1;
+ }
+ shared_resource->alloc_private_data_sizes =
+ vzalloc(sizeof(u32)*shared_resource->allocation_count);
+ if (shared_resource->alloc_private_data_sizes == NULL) {
+ ret = -EINVAL;
+ goto cleanup1;
+ }
+ private_data = shared_resource->alloc_private_data;
+ data_size = shared_resource->alloc_private_data_size;
+ i = 0;
+ list_for_each_entry(alloc, &resource->alloc_list_head,
+ alloc_list_entry) {
+ u32 alloc_data_size = alloc->priv_drv_data->data_size;
+
+ if (alloc_data_size) {
+ if (data_size < alloc_data_size) {
+ pr_err("Invalid private data size");
+ ret = -EINVAL;
+ goto cleanup1;
+ }
+ shared_resource->alloc_private_data_sizes[i] =
+ alloc_data_size;
+ memcpy(private_data,
+ alloc->priv_drv_data->data,
+ alloc_data_size);
+ vfree(alloc->priv_drv_data);
+ alloc->priv_drv_data = NULL;
+ private_data += alloc_data_size;
+ data_size -= alloc_data_size;
+ }
+ i++;
+ }
+ if (data_size != 0) {
+ pr_err("Data size mismatch");
+ ret = -EINVAL;
+ }
+cleanup1:
+ mutex_unlock(&resource->resource_mutex);
+ }
+cleanup:
+ up_write(&shared_resource->adapter->shared_resource_list_lock);
+ return ret;
+}
+
static int
dxgk_enum_adapters(struct dxgprocess *process, void *__user inargs)
{
@@ -1644,6 +1790,148 @@ dxgk_destroy_sync_object(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgk_open_sync_object_nt(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_opensyncobjectfromnthandle2 args;
+ struct dxgsyncobject *syncobj = NULL;
+ struct dxgsharedsyncobject *syncobj_fd = NULL;
+ struct file *file = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct d3dddi_synchronizationobject_flags flags = { };
+ int ret;
+ bool device_lock_acquired = false;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ args.sync_object.v = 0;
+
+ if (args.device.v) {
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ return -EINVAL;
+ goto cleanup;
+ }
+ } else {
+ pr_err("device handle is missing");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0)
+ goto cleanup;
+
+ device_lock_acquired = true;
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ file = fget(args.nt_handle);
+ if (!file) {
+ pr_err("failed to get file from handle: %llx",
+ args.nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (file->f_op != &dxg_syncobj_fops) {
+ pr_err("invalid fd: %llx", args.nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ syncobj_fd = file->private_data;
+ if (syncobj_fd == NULL) {
+ pr_err("invalid private data: %llx", args.nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ flags.shared = 1;
+ flags.nt_security_sharing = 1;
+ syncobj = dxgsyncobject_create(process, device, adapter,
+ syncobj_fd->type, flags);
+ if (syncobj == NULL) {
+ pr_err("failed to create sync object");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ dxgsharedsyncobj_add_syncobj(syncobj_fd, syncobj);
+
+ ret = dxgvmb_send_open_sync_object_nt(process, &dxgglobal->channel,
+ &args, syncobj);
+ if (ret < 0) {
+ pr_err("failed to open sync object on host: %x",
+ syncobj_fd->host_shared_handle.v);
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(&process->handle_table, syncobj,
+ HMGRENTRY_TYPE_DXGSYNCOBJECT,
+ args.sync_object);
+ if (ret >= 0) {
+ syncobj->handle = args.sync_object;
+ kref_get(&syncobj->syncobj_kref);
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret >= 0)
+ goto success;
+ pr_err("%s failed to copy output args", __func__);
+
+cleanup:
+
+ if (syncobj) {
+ dxgsyncobject_destroy(process, syncobj);
+ syncobj = NULL;
+ }
+
+ if (args.sync_object.v)
+ dxgvmb_send_destroy_sync_object(process, args.sync_object);
+
+success:
+
+ if (file)
+ fput(file);
+ if (syncobj)
+ kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device_lock_acquired)
+ dxgdevice_release_lock_shared(device);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_open_sync_object(struct dxgprocess *process, void *__user inargs)
+{
+ pr_err("%s is not supported", __func__);
+ return -ENOTTY;
+}
+
static int
dxgk_signal_sync_object(struct dxgprocess *process, void *__user inargs)
{
@@ -2123,10 +2411,13 @@ dxgk_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
if (args.async_event == 0) {
dxgadapter_release_lock_shared(adapter);
adapter = NULL;
- ret = wait_for_completion_killable(&local_event);
- if (ret)
- pr_err("%s: wait_for_completion_killable failed: %d",
+ ret = wait_for_completion_interruptible(&local_event);
+ if (ret) {
+ pr_err("%s: wait_completion_interruptible failed: %d",
__func__, ret);
+ ret = -ERESTARTSYS;
+ }
+
}
cleanup:
@@ -2295,6 +2586,631 @@ dxgk_wait_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj,
+ struct dxgprocess *process,
+ struct d3dkmthandle objecthandle)
+{
+ int ret = 0;
+
+ mutex_lock(&syncobj->fd_mutex);
+ if (syncobj->host_shared_handle_nt_reference == 0) {
+ ret = dxgvmb_send_create_nt_shared_object(process,
+ objecthandle,
+ &syncobj->host_shared_handle_nt);
+ if (ret < 0)
+ goto cleanup;
+ dev_dbg(dxgglobaldev, "Host_shared_handle_ht: %x",
+ syncobj->host_shared_handle_nt.v);
+ kref_get(&syncobj->ssyncobj_kref);
+ }
+ syncobj->host_shared_handle_nt_reference++;
+cleanup:
+ mutex_unlock(&syncobj->fd_mutex);
+ return ret;
+}
+
+static int
+dxgsharedresource_get_host_nt_handle(struct dxgsharedresource *resource,
+ struct dxgprocess *process,
+ struct d3dkmthandle objecthandle)
+{
+ int ret = 0;
+
+ mutex_lock(&resource->fd_mutex);
+ if (resource->host_shared_handle_nt_reference == 0) {
+ ret = dxgvmb_send_create_nt_shared_object(process,
+ objecthandle,
+ &resource->host_shared_handle_nt);
+ if (ret < 0)
+ goto cleanup;
+ dev_dbg(dxgglobaldev, "Resource host_shared_handle_ht: %x",
+ resource->host_shared_handle_nt.v);
+ kref_get(&resource->sresource_kref);
+ }
+ resource->host_shared_handle_nt_reference++;
+cleanup:
+ mutex_unlock(&resource->fd_mutex);
+ return ret;
+}
+
+enum dxg_sharedobject_type {
+ DXG_SHARED_SYNCOBJECT,
+ DXG_SHARED_RESOURCE
+};
+
+static int get_object_fd(enum dxg_sharedobject_type type,
+ void *object, int *fdout)
+{
+ struct file *file;
+ int fd;
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fd < 0) {
+ pr_err("get_unused_fd_flags failed: %x", fd);
+ return -ENOTRECOVERABLE;
+ }
+
+ switch (type) {
+ case DXG_SHARED_SYNCOBJECT:
+ file = anon_inode_getfile("dxgsyncobj",
+ &dxg_syncobj_fops, object, 0);
+ break;
+ case DXG_SHARED_RESOURCE:
+ file = anon_inode_getfile("dxgresource",
+ &dxg_resource_fops, object, 0);
+ break;
+ default:
+ return -EINVAL;
+ };
+ if (IS_ERR(file)) {
+ pr_err("anon_inode_getfile failed: %x", fd);
+ put_unused_fd(fd);
+ return -ENOTRECOVERABLE;
+ }
+
+ fd_install(fd, file);
+ *fdout = fd;
+ return 0;
+}
+
+static int
+dxgk_share_objects(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_shareobjects args;
+ enum hmgrentry_type object_type;
+ struct dxgsyncobject *syncobj = NULL;
+ struct dxgresource *resource = NULL;
+ struct dxgsharedsyncobject *shared_syncobj = NULL;
+ struct dxgsharedresource *shared_resource = NULL;
+ struct d3dkmthandle *handles = NULL;
+ int object_fd = 0;
+ void *obj = NULL;
+ u32 handle_size;
+ int ret;
+ u64 tmp = 0;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.object_count == 0 || args.object_count > 1) {
+ pr_err("invalid object count %d", args.object_count);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ handle_size = args.object_count * sizeof(struct d3dkmthandle);
+
+ handles = vzalloc(handle_size);
+ if (handles == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret = copy_from_user(handles, args.objects, handle_size);
+ if (ret) {
+ pr_err("%s failed to copy object handles", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dev_dbg(dxgglobaldev, "Sharing handle: %x", handles[0].v);
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED);
+ object_type = hmgrtable_get_object_type(&process->handle_table,
+ handles[0]);
+ obj = hmgrtable_get_object(&process->handle_table, handles[0]);
+ if (obj == NULL) {
+ pr_err("invalid object handle %x", handles[0].v);
+ ret = -EINVAL;
+ } else {
+ switch (object_type) {
+ case HMGRENTRY_TYPE_DXGSYNCOBJECT:
+ syncobj = obj;
+ if (syncobj->shared) {
+ kref_get(&syncobj->syncobj_kref);
+ shared_syncobj = syncobj->shared_owner;
+ } else {
+ pr_err("sync object is not shared");
+ syncobj = NULL;
+ ret = -EINVAL;
+ }
+ break;
+ case HMGRENTRY_TYPE_DXGRESOURCE:
+ resource = obj;
+ if (resource->shared_owner) {
+ kref_get(&resource->resource_kref);
+ shared_resource = resource->shared_owner;
+ } else {
+ resource = NULL;
+ pr_err("resource object is not shared");
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ pr_err("invalid object type %d", object_type);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED);
+
+ if (ret < 0)
+ goto cleanup;
+
+ switch (object_type) {
+ case HMGRENTRY_TYPE_DXGSYNCOBJECT:
+ ret = get_object_fd(DXG_SHARED_SYNCOBJECT, shared_syncobj,
+ &object_fd);
+ if (ret >= 0)
+ ret =
+ dxgsharedsyncobj_get_host_nt_handle(shared_syncobj,
+ process,
+ handles[0]);
+ break;
+ case HMGRENTRY_TYPE_DXGRESOURCE:
+ ret = get_object_fd(DXG_SHARED_RESOURCE, shared_resource,
+ &object_fd);
+ if (ret >= 0)
+ ret = dxgsharedresource_get_host_nt_handle(
+ shared_resource, process, handles[0]);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret < 0)
+ goto cleanup;
+
+ dev_dbg(dxgglobaldev, "Object FD: %x", object_fd);
+
+ tmp = (u64) object_fd;
+
+ ret = copy_to_user(args.shared_handle, &tmp, sizeof(u64));
+ if (ret < 0)
+ pr_err("%s failed to copy shared handle", __func__);
+
+cleanup:
+ if (ret < 0) {
+ if (object_fd > 0)
+ put_unused_fd(object_fd);
+ }
+
+ if (handles)
+ vfree(handles);
+
+ if (syncobj)
+ kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
+
+ if (resource)
+ kref_put(&resource->resource_kref, dxgresource_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_query_resource_info(struct dxgprocess *process, void *__user inargs)
+{
+ pr_err("%s is not supported", __func__);
+ return -ENOTTY;
+}
+
+static int
+dxgk_query_resource_info_nt(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_queryresourceinfofromnthandle args;
+ int ret;
+ struct dxgdevice *device = NULL;
+ struct dxgsharedresource *shared_resource = NULL;
+ struct file *file = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ file = fget(args.nt_handle);
+ if (!file) {
+ pr_err("failed to get file from handle: %llx",
+ args.nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (file->f_op != &dxg_resource_fops) {
+ pr_err("invalid fd: %llx", args.nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ shared_resource = file->private_data;
+ if (shared_resource == NULL) {
+ pr_err("invalid private data: %llx", args.nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ kref_put(&device->device_kref, dxgdevice_release);
+ device = NULL;
+ goto cleanup;
+ }
+
+ ret = dxgsharedresource_seal(shared_resource);
+ if (ret < 0)
+ goto cleanup;
+
+ args.private_runtime_data_size =
+ shared_resource->runtime_private_data_size;
+ args.resource_priv_drv_data_size =
+ shared_resource->resource_private_data_size;
+ args.allocation_count = shared_resource->allocation_count;
+ args.total_priv_drv_data_size =
+ shared_resource->alloc_private_data_size;
+
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret < 0)
+ pr_err("%s failed to copy output args", __func__);
+
+cleanup:
+
+ if (file)
+ fput(file);
+ if (device)
+ dxgdevice_release_lock_shared(device);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+int
+assign_resource_handles(struct dxgprocess *process,
+ struct dxgsharedresource *shared_resource,
+ struct d3dkmt_openresourcefromnthandle *args,
+ struct d3dkmthandle resource_handle,
+ struct dxgresource *resource,
+ struct dxgallocation **allocs,
+ struct d3dkmthandle *handles)
+{
+ int ret;
+ int i;
+ u8 *cur_priv_data;
+ u32 total_priv_data_size = 0;
+ struct d3dddi_openallocationinfo2 open_alloc_info = { };
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(&process->handle_table, resource,
+ HMGRENTRY_TYPE_DXGRESOURCE,
+ resource_handle);
+ if (ret < 0)
+ goto cleanup;
+ resource->handle = resource_handle;
+ resource->handle_valid = 1;
+ cur_priv_data = args->total_priv_drv_data;
+ for (i = 0; i < args->allocation_count; i++) {
+ ret = hmgrtable_assign_handle(&process->handle_table, allocs[i],
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ handles[i]);
+ if (ret < 0)
+ goto cleanup;
+ allocs[i]->alloc_handle = handles[i];
+ allocs[i]->handle_valid = 1;
+ open_alloc_info.allocation = handles[i];
+ if (shared_resource->alloc_private_data_sizes)
+ open_alloc_info.priv_drv_data_size =
+ shared_resource->alloc_private_data_sizes[i];
+ else
+ open_alloc_info.priv_drv_data_size = 0;
+
+ total_priv_data_size += open_alloc_info.priv_drv_data_size;
+ open_alloc_info.priv_drv_data = cur_priv_data;
+ cur_priv_data += open_alloc_info.priv_drv_data_size;
+
+ ret = copy_to_user(&args->open_alloc_info[i],
+ &open_alloc_info,
+ sizeof(open_alloc_info));
+ if (ret < 0) {
+ pr_err("%s failed to copy alloc info", __func__);
+ goto cleanup;
+ }
+ }
+ args->total_priv_drv_data_size = total_priv_data_size;
+cleanup:
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+ if (ret < 0) {
+ for (i = 0; i < args->allocation_count; i++)
+ dxgallocation_free_handle(allocs[i]);
+ dxgresource_free_handle(resource);
+ }
+ dev_dbg(dxgglobaldev, "%s end %x", __func__, ret);
+ return ret;
+}
+
+int
+open_resource(struct dxgprocess *process,
+ struct d3dkmt_openresourcefromnthandle *args,
+ __user struct d3dkmthandle *res_out,
+ __user u32 *total_driver_data_size_out)
+{
+ int ret = 0;
+ int i;
+ struct d3dkmthandle *alloc_handles = NULL;
+ int alloc_handles_size = sizeof(struct d3dkmthandle) *
+ args->allocation_count;
+ struct dxgsharedresource *shared_resource = NULL;
+ struct dxgresource *resource = NULL;
+ struct dxgallocation **allocs = NULL;
+ struct d3dkmthandle global_share = {};
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct d3dkmthandle resource_handle = {};
+ struct file *file = NULL;
+
+ dev_dbg(dxgglobaldev, "Opening resource handle: %llx", args->nt_handle);
+
+ file = fget(args->nt_handle);
+ if (!file) {
+ pr_err("failed to get file from handle: %llx",
+ args->nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (file->f_op != &dxg_resource_fops) {
+ pr_err("invalid fd type: %llx", args->nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ shared_resource = file->private_data;
+ if (shared_resource == NULL) {
+ pr_err("invalid private data: %llx",
+ args->nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (kref_get_unless_zero(&shared_resource->sresource_kref) == 0)
+ shared_resource = NULL;
+ else
+ global_share = shared_resource->host_shared_handle_nt;
+
+ if (shared_resource == NULL) {
+ pr_err("Invalid shared resource handle: %x",
+ (u32)args->nt_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dev_dbg(dxgglobaldev, "Shared resource: %p %x", shared_resource,
+ global_share.v);
+
+ device = dxgprocess_device_by_handle(process, args->device);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ kref_put(&device->device_kref, dxgdevice_release);
+ device = NULL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ ret = dxgsharedresource_seal(shared_resource);
+ if (ret < 0)
+ goto cleanup;
+
+ if (args->allocation_count != shared_resource->allocation_count ||
+ args->private_runtime_data_size <
+ shared_resource->runtime_private_data_size ||
+ args->resource_priv_drv_data_size <
+ shared_resource->resource_private_data_size ||
+ args->total_priv_drv_data_size <
+ shared_resource->alloc_private_data_size) {
+ ret = -EINVAL;
+ pr_err("Invalid data sizes");
+ goto cleanup;
+ }
+
+ alloc_handles = vzalloc(alloc_handles_size);
+ if (alloc_handles == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ allocs = vzalloc(sizeof(void *) * args->allocation_count);
+ if (allocs == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ resource = dxgresource_create(device);
+ if (resource == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ dxgsharedresource_add_resource(shared_resource, resource);
+
+ for (i = 0; i < args->allocation_count; i++) {
+ allocs[i] = dxgallocation_create(process);
+ if (allocs[i] == NULL)
+ goto cleanup;
+ ret = dxgresource_add_alloc(resource, allocs[i]);
+ if (ret < 0)
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_open_resource(process, adapter,
+ device->handle, global_share,
+ args->allocation_count,
+ args->total_priv_drv_data_size,
+ &resource_handle, alloc_handles);
+ if (ret < 0) {
+ pr_err("dxgvmb_send_open_resource failed");
+ goto cleanup;
+ }
+
+ if (shared_resource->runtime_private_data_size) {
+ ret = copy_to_user(args->private_runtime_data,
+ shared_resource->runtime_private_data,
+ shared_resource->runtime_private_data_size);
+ if (ret < 0) {
+ pr_err("%s failed to copy runtime data", __func__);
+ goto cleanup;
+ }
+ }
+
+ if (shared_resource->resource_private_data_size) {
+ ret = copy_to_user(args->resource_priv_drv_data,
+ shared_resource->resource_private_data,
+ shared_resource->resource_private_data_size);
+ if (ret < 0) {
+ pr_err("%s failed to copy resource data", __func__);
+ goto cleanup;
+ }
+ }
+
+ if (shared_resource->alloc_private_data_size) {
+ ret = copy_to_user(args->total_priv_drv_data,
+ shared_resource->alloc_private_data,
+ shared_resource->alloc_private_data_size);
+ if (ret < 0) {
+ pr_err("%s failed to copy alloc data", __func__);
+ goto cleanup;
+ }
+ }
+
+ ret = assign_resource_handles(process, shared_resource, args,
+ resource_handle, resource, allocs,
+ alloc_handles);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(res_out, &resource_handle,
+ sizeof(struct d3dkmthandle));
+ if (ret < 0) {
+ pr_err("%s failed to copy resource handle to user", __func__);
+ goto cleanup;
+ }
+
+ ret = copy_to_user(total_driver_data_size_out,
+ &args->total_priv_drv_data_size, sizeof(u32));
+ if (ret < 0)
+ pr_err("%s failed to copy total driver data size", __func__);
+
+cleanup:
+
+ if (ret < 0) {
+ if (resource_handle.v) {
+ struct d3dkmt_destroyallocation2 tmp = { };
+
+ tmp.flags.assume_not_in_use = 1;
+ tmp.device = args->device;
+ tmp.resource = resource_handle;
+ ret = dxgvmb_send_destroy_allocation(process, device,
+ &tmp, NULL);
+ }
+ if (resource)
+ dxgresource_destroy(resource);
+ }
+
+ if (file)
+ fput(file);
+ if (allocs)
+ vfree(allocs);
+ if (shared_resource)
+ kref_put(&shared_resource->sresource_kref,
+ dxgsharedresource_destroy);
+ if (alloc_handles)
+ vfree(alloc_handles);
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ dxgdevice_release_lock_shared(device);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ return ret;
+}
+
+static int
+dxgk_open_resource(struct dxgprocess *process, void *__user inargs)
+{
+ pr_err("%s is not supported", __func__);
+ return -ENOTTY;
+}
+
+static int
+dxgk_open_resource_nt(struct dxgprocess *process,
+ void *__user inargs)
+{
+ struct d3dkmt_openresourcefromnthandle args;
+ struct d3dkmt_openresourcefromnthandle *__user args_user = inargs;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = open_resource(process, &args,
+ &args_user->resource,
+ &args_user->total_priv_drv_data_size);
+
+cleanup:
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
static int
dxgk_render(struct dxgprocess *process, void *__user inargs)
{
@@ -2409,6 +3325,12 @@ void init_ioctls(void)
LX_DXDESTROYSYNCHRONIZATIONOBJECT);
SET_IOCTL(/*0x23 */ dxgk_get_shared_resource_adapter_luid,
LX_DXGETSHAREDRESOURCEADAPTERLUID);
+ SET_IOCTL(/*0x28 */ dxgk_open_resource,
+ LX_DXOPENRESOURCE);
+ SET_IOCTL(/*0x29 */ dxgk_open_sync_object,
+ LX_DXOPENSYNCHRONIZATIONOBJECT);
+ SET_IOCTL(/*0x2b */ dxgk_query_resource_info,
+ LX_DXQUERYRESOURCEINFO);
SET_IOCTL(/*0x2d */ dxgk_render,
LX_DXRENDER);
SET_IOCTL(/*0x31 */ dxgk_signal_sync_object_cpu,
@@ -2423,4 +3345,12 @@ void init_ioctls(void)
LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU);
SET_IOCTL(/*0x3e */ dxgk_enum_adapters3,
LX_DXENUMADAPTERS3);
+ SET_IOCTL(/*0x3f */ dxgk_share_objects,
+ LX_DXSHAREOBJECTS);
+ SET_IOCTL(/*0x40 */ dxgk_open_sync_object_nt,
+ LX_DXOPENSYNCOBJECTFROMNTHANDLE2);
+ SET_IOCTL(/*0x41 */ dxgk_query_resource_info_nt,
+ LX_DXQUERYRESOURCEINFOFROMNTHANDLE);
+ SET_IOCTL(/*0x42 */ dxgk_open_resource_nt,
+ LX_DXOPENRESOURCEFROMNTHANDLE);
}
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* [PATCH v1 6/9] drivers: hv: dxgkrnl: Seal the shared resource object when dxgk_share_objects is called.
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
` (3 preceding siblings ...)
2022-01-12 19:55 ` [PATCH v1 5/9] drivers: hv: dxgkrnl: Implement sharing resources and " Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-12 19:55 ` [PATCH v1 7/9] drivers: hv: dxgkrnl: Implementation of submit command, paging and hardware queue Iouri Tarassov
` (4 subsequent siblings)
9 siblings, 0 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
A dxgresource object is a collection of dxgallocation objects.
The WDDM API allows addition/removal allocations to a resource.
The WDDM API has limitations on addition/removal of allocations to
a shared resource. When a resource is "sealed", addition/removal of
allocations is not allowed.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/ioctl.c | 36 ++++++++++++++++++++++++++++--------
1 file changed, 28 insertions(+), 8 deletions(-)
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 2086f7347ba3..97f4d2471ca5 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -2767,18 +2767,38 @@ dxgk_share_objects(struct dxgprocess *process, void *__user inargs)
case HMGRENTRY_TYPE_DXGSYNCOBJECT:
ret = get_object_fd(DXG_SHARED_SYNCOBJECT, shared_syncobj,
&object_fd);
- if (ret >= 0)
- ret =
- dxgsharedsyncobj_get_host_nt_handle(shared_syncobj,
- process,
- handles[0]);
+ if (ret < 0) {
+ pr_err("%s get_object_fd failed for sync object",
+ __func__);
+ goto cleanup;
+ }
+ ret = dxgsharedsyncobj_get_host_nt_handle(shared_syncobj,
+ process,
+ handles[0]);
+ if (ret < 0) {
+ pr_err("%s get_host_nt_handle failed", __func__);
+ goto cleanup;
+ }
break;
case HMGRENTRY_TYPE_DXGRESOURCE:
ret = get_object_fd(DXG_SHARED_RESOURCE, shared_resource,
&object_fd);
- if (ret >= 0)
- ret = dxgsharedresource_get_host_nt_handle(
- shared_resource, process, handles[0]);
+ if (ret < 0) {
+ pr_err("%s get_object_fd failed for resource",
+ __func__);
+ goto cleanup;
+ }
+ ret = dxgsharedresource_get_host_nt_handle(shared_resource,
+ process, handles[0]);
+ if (ret < 0) {
+ pr_err("%s get_host_res_nt_handle failed", __func__);
+ goto cleanup;
+ }
+ ret = dxgsharedresource_seal(shared_resource);
+ if (ret < 0) {
+ pr_err("%s dxgsharedresource_seal failed", __func__);
+ goto cleanup;
+ }
break;
default:
ret = -EINVAL;
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* [PATCH v1 7/9] drivers: hv: dxgkrnl: Implementation of submit command, paging and hardware queue.
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
` (4 preceding siblings ...)
2022-01-12 19:55 ` [PATCH v1 6/9] drivers: hv: dxgkrnl: Seal the shared resource object when dxgk_share_objects is called Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-12 19:55 ` [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls Iouri Tarassov
` (3 subsequent siblings)
9 siblings, 0 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
Implement various IOCTLs to deal with hardware queues and paging queues.
Hardware queues are used when a compute device supports "hardware
scheduling". This means that the compute device itself schedules execution
of DMA buffers from hardware queues without CPU intervention. This is as
oppose to the "packet scheduling" mode where the software GPU scheduler
on the host schedules DMA buffer execution.
LX_DXSUBMITCOMMAND
This IOCTL is used to submit GPU commands when the device supports the
"packet scheduling" mode.
LX_DXSUBMITCOMMANDTOHWQUEUE
This IOCTL is used to submit GPU commands when the device supports the
"hardware scheduling" mode.
LX_DXCREATEPAGINGQUEUE, LX_DXDESTROYPAGINGQUEUE
These IOCTLs are used to create/destroy a paging queue.
Paging queues are used to handle residency of device accessible
allocations. An allocation is resident, when the device has access to
it. For example, the allocation resides in local device memory or
device page tables point to system memory which is made non-pageable.
LX_DXCREATEHWQUEUE, LX_DXDESTROYHWQUEUE
These IOCTLs are used to create/destroy hardware queue objects.
Hardware queues are used when the compute device supports the
"hardware scheduling" mode.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 164 ++++++++-
drivers/hv/dxgkrnl/dxgvmbus.c | 341 +++++++++++++++++
drivers/hv/dxgkrnl/ioctl.c | 634 ++++++++++++++++++++++++++++++++
3 files changed, 1130 insertions(+), 9 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index da6d7c4a7dc5..e7424f549c56 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -728,6 +728,26 @@ void dxgdevice_release(struct kref *refcount)
vfree(device);
}
+void dxgdevice_add_paging_queue(struct dxgdevice *device,
+ struct dxgpagingqueue *entry)
+{
+ dxgdevice_acquire_alloc_list_lock(device);
+ list_add_tail(&entry->pqueue_list_entry, &device->pqueue_list_head);
+ dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_paging_queue(struct dxgpagingqueue *pqueue)
+{
+ struct dxgdevice *device = pqueue->device;
+
+ dxgdevice_acquire_alloc_list_lock(device);
+ if (pqueue->pqueue_list_entry.next) {
+ list_del(&pqueue->pqueue_list_entry);
+ pqueue->pqueue_list_entry.next = NULL;
+ }
+ dxgdevice_release_alloc_list_lock(device);
+}
+
void dxgdevice_add_syncobj(struct dxgdevice *device,
struct dxgsyncobject *syncobj)
{
@@ -819,6 +839,38 @@ void dxgcontext_release(struct kref *refcount)
vfree(context);
}
+int dxgcontext_add_hwqueue(struct dxgcontext *context,
+ struct dxghwqueue *hwqueue)
+{
+ int ret = 0;
+
+ down_write(&context->hwqueue_list_lock);
+ if (dxgcontext_is_active(context))
+ list_add_tail(&hwqueue->hwqueue_list_entry,
+ &context->hwqueue_list_head);
+ else
+ ret = -ENODEV;
+ up_write(&context->hwqueue_list_lock);
+ return ret;
+}
+
+void dxgcontext_remove_hwqueue(struct dxgcontext *context,
+ struct dxghwqueue *hwqueue)
+{
+ if (hwqueue->hwqueue_list_entry.next) {
+ list_del(&hwqueue->hwqueue_list_entry);
+ hwqueue->hwqueue_list_entry.next = NULL;
+ }
+}
+
+void dxgcontext_remove_hwqueue_safe(struct dxgcontext *context,
+ struct dxghwqueue *hwqueue)
+{
+ down_write(&context->hwqueue_list_lock);
+ dxgcontext_remove_hwqueue(context, hwqueue);
+ up_write(&context->hwqueue_list_lock);
+}
+
struct dxgallocation *dxgallocation_create(struct dxgprocess *process)
{
struct dxgallocation *alloc = vzalloc(sizeof(struct dxgallocation));
@@ -890,6 +942,59 @@ void dxgallocation_destroy(struct dxgallocation *alloc)
vfree(alloc);
}
+struct dxgpagingqueue *dxgpagingqueue_create(struct dxgdevice *device)
+{
+ struct dxgpagingqueue *pqueue;
+
+ pqueue = vzalloc(sizeof(*pqueue));
+ if (pqueue) {
+ pqueue->device = device;
+ pqueue->process = device->process;
+ pqueue->device_handle = device->handle;
+ dxgdevice_add_paging_queue(device, pqueue);
+ }
+ return pqueue;
+}
+
+void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue)
+{
+ int ret;
+
+ if (pqueue->mapped_address) {
+ ret = dxg_unmap_iospace(pqueue->mapped_address, PAGE_SIZE);
+ dev_dbg(dxgglobaldev, "fence is unmapped %d %p",
+ ret, pqueue->mapped_address);
+ pqueue->mapped_address = NULL;
+ }
+}
+
+void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue)
+{
+ struct dxgprocess *process = pqueue->process;
+
+ dev_dbg(dxgglobaldev, "%s %p %x\n", __func__, pqueue, pqueue->handle.v);
+
+ dxgpagingqueue_stop(pqueue);
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ if (pqueue->handle.v) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ pqueue->handle);
+ pqueue->handle.v = 0;
+ }
+ if (pqueue->syncobj_handle.v) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_MONITOREDFENCE,
+ pqueue->syncobj_handle);
+ pqueue->syncobj_handle.v = 0;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+ if (pqueue->device)
+ dxgdevice_remove_paging_queue(pqueue);
+ vfree(pqueue);
+}
+
struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
struct dxgadapter *adapter)
{
@@ -1188,8 +1293,8 @@ void dxgsyncobject_stop(struct dxgsyncobject *syncobj)
PAGE_SIZE);
(void)ret;
- dev_dbg(dxgglobaldev, "fence is unmapped %d %p\n",
- ret, syncobj->mapped_address);
+ dev_dbg(dxgglobaldev, "unmap fence %d %p\n",
+ ret, syncobj->mapped_address);
syncobj->mapped_address = NULL;
}
}
@@ -1212,18 +1317,59 @@ void dxgsyncobject_release(struct kref *refcount)
vfree(syncobj);
}
-void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwqueue)
+struct dxghwqueue *dxghwqueue_create(struct dxgcontext *context)
{
- /* Placeholder */
+ struct dxgprocess *process = context->device->process;
+ struct dxghwqueue *hwqueue = vzalloc(sizeof(*hwqueue));
+
+ if (hwqueue) {
+ kref_init(&hwqueue->hwqueue_kref);
+ hwqueue->context = context;
+ hwqueue->process = process;
+ hwqueue->device_handle = context->device->handle;
+ if (dxgcontext_add_hwqueue(context, hwqueue) < 0) {
+ kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release);
+ hwqueue = NULL;
+ } else {
+ kref_get(&context->context_kref);
+ }
+ }
+ return hwqueue;
}
-void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue)
+void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwqueue)
{
- /* Placeholder */
+ dev_dbg(dxgglobaldev, "%s %p\n", __func__, hwqueue);
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ if (hwqueue->handle.v) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ hwqueue->handle);
+ hwqueue->handle.v = 0;
+ }
+ if (hwqueue->progress_fence_sync_object.v) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_MONITOREDFENCE,
+ hwqueue->progress_fence_sync_object);
+ hwqueue->progress_fence_sync_object.v = 0;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (hwqueue->progress_fence_mapped_address) {
+ dxg_unmap_iospace(hwqueue->progress_fence_mapped_address,
+ PAGE_SIZE);
+ hwqueue->progress_fence_mapped_address = NULL;
+ }
+ dxgcontext_remove_hwqueue_safe(hwqueue->context, hwqueue);
+
+ kref_put(&hwqueue->context->context_kref, dxgcontext_release);
+ kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release);
}
-void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue)
+void dxghwqueue_release(struct kref *refcount)
{
- /* Placeholder */
-}
+ struct dxghwqueue *hwqueue;
+ hwqueue = container_of(refcount, struct dxghwqueue, hwqueue_kref);
+ vfree(hwqueue);
+}
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 6fc0771f383d..67ff8bcbfb9a 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1106,6 +1106,80 @@ int dxgvmb_send_destroy_context(struct dxgadapter *adapter,
return ret;
}
+int dxgvmb_send_create_paging_queue(struct dxgprocess *process,
+ struct dxgdevice *device,
+ struct d3dkmt_createpagingqueue *args,
+ struct dxgpagingqueue *pqueue)
+{
+ struct dxgkvmb_command_createpagingqueue_return result;
+ struct dxgkvmb_command_createpagingqueue *command;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, device->adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_CREATEPAGINGQUEUE,
+ process->host_handle);
+ command->args = *args;
+ args->paging_queue.v = 0;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result,
+ sizeof(result));
+ if (ret < 0) {
+ pr_err("send_create_paging_queue failed %x", ret);
+ goto cleanup;
+ }
+
+ args->paging_queue = result.paging_queue;
+ args->sync_object = result.sync_object;
+ args->fence_cpu_virtual_address =
+ dxg_map_iospace(result.fence_storage_physical_address, PAGE_SIZE,
+ PROT_READ | PROT_WRITE, true);
+ if (args->fence_cpu_virtual_address == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ pqueue->mapped_address = args->fence_cpu_virtual_address;
+ pqueue->handle = args->paging_queue;
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_destroy_paging_queue(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle h)
+{
+ int ret;
+ struct dxgkvmb_command_destroypagingqueue *command;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_DESTROYPAGINGQUEUE,
+ process->host_handle);
+ command->paging_queue = h;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, NULL, 0);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
static int
copy_private_data(struct d3dkmt_createallocation *args,
struct dxgkvmb_command_createallocation *command,
@@ -1770,6 +1844,60 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
return ret;
}
+int dxgvmb_send_submit_command(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_submitcommand *args)
+{
+ int ret;
+ u32 cmd_size;
+ struct dxgkvmb_command_submitcommand *command;
+ u32 hbufsize = args->num_history_buffers * sizeof(struct d3dkmthandle);
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ cmd_size = sizeof(struct dxgkvmb_command_submitcommand) +
+ hbufsize + args->priv_drv_data_size;
+
+ ret = init_message(&msg, adapter, process, cmd_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ ret = copy_from_user(&command[1], args->history_buffer_array,
+ hbufsize);
+ if (ret) {
+ pr_err("%s failed to copy history buffer", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_from_user((u8 *) &command[1] + hbufsize,
+ args->priv_drv_data, args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy history priv data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_SUBMITCOMMAND,
+ process->host_handle);
+ command->args = *args;
+
+ 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)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
static void set_result(struct d3dkmt_createsynchronizationobject2 *args,
u64 fence_gpu_va, u8 *va)
{
@@ -2052,6 +2180,161 @@ int dxgvmb_send_wait_sync_object_gpu(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_createhwqueue *args,
+ struct d3dkmt_createhwqueue *__user inargs,
+ struct dxghwqueue *hwqueue)
+{
+ struct dxgkvmb_command_createhwqueue *command = NULL;
+ u32 cmd_size = sizeof(struct dxgkvmb_command_createhwqueue);
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ if (args->priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ pr_err("invalid private driver data size");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args->priv_drv_data_size)
+ cmd_size += args->priv_drv_data_size - 1;
+
+ 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_CREATEHWQUEUE,
+ process->host_handle);
+ command->context = args->context;
+ command->flags = args->flags;
+ command->priv_drv_data_size = args->priv_drv_data_size;
+ if (args->priv_drv_data_size) {
+ ret = copy_from_user(command->priv_drv_data,
+ args->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy private data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ command, cmd_size);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(command->status);
+ if (ret < 0) {
+ pr_err("dxgvmb_send_sync_msg failed: %x", command->status.v);
+ goto cleanup;
+ }
+
+ ret = hmgrtable_assign_handle_safe(&process->handle_table, hwqueue,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ command->hwqueue);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = hmgrtable_assign_handle_safe(&process->handle_table,
+ NULL,
+ HMGRENTRY_TYPE_MONITOREDFENCE,
+ command->hwqueue_progress_fence);
+ if (ret < 0)
+ goto cleanup;
+
+ hwqueue->handle = command->hwqueue;
+ hwqueue->progress_fence_sync_object = command->hwqueue_progress_fence;
+
+ hwqueue->progress_fence_mapped_address =
+ dxg_map_iospace((u64)command->hwqueue_progress_fence_cpuva,
+ PAGE_SIZE, PROT_READ | PROT_WRITE, true);
+ if (hwqueue->progress_fence_mapped_address == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = copy_to_user(&inargs->queue, &command->hwqueue,
+ sizeof(struct d3dkmthandle));
+ if (ret < 0) {
+ pr_err("%s failed to copy hwqueue handle", __func__);
+ goto cleanup;
+ }
+ ret = copy_to_user(&inargs->queue_progress_fence,
+ &command->hwqueue_progress_fence,
+ sizeof(struct d3dkmthandle));
+ if (ret < 0) {
+ pr_err("%s failed to progress fence", __func__);
+ goto cleanup;
+ }
+ ret = copy_to_user(&inargs->queue_progress_fence_cpu_va,
+ &hwqueue->progress_fence_mapped_address,
+ sizeof(inargs->queue_progress_fence_cpu_va));
+ if (ret < 0) {
+ pr_err("%s failed to copy fence cpu va", __func__);
+ goto cleanup;
+ }
+ ret = copy_to_user(&inargs->queue_progress_fence_gpu_va,
+ &command->hwqueue_progress_fence_gpuva,
+ sizeof(u64));
+ if (ret < 0) {
+ pr_err("%s failed to copy fence gpu va", __func__);
+ goto cleanup;
+ }
+ if (args->priv_drv_data_size) {
+ ret = copy_to_user(args->priv_drv_data,
+ command->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret < 0)
+ pr_err("%s failed to copy private data", __func__);
+ }
+
+cleanup:
+ if (ret < 0) {
+ pr_err("%s failed %x", __func__, ret);
+ if (hwqueue->handle.v) {
+ hmgrtable_free_handle_safe(&process->handle_table,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ hwqueue->handle);
+ hwqueue->handle.v = 0;
+ }
+ if (command && command->hwqueue.v)
+ dxgvmb_send_destroy_hwqueue(process, adapter,
+ command->hwqueue);
+ }
+ free_message(&msg, process);
+ return ret;
+}
+
+int dxgvmb_send_destroy_hwqueue(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle handle)
+{
+ int ret;
+ struct dxgkvmb_command_destroyhwqueue *command;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_DESTROYHWQUEUE,
+ process->host_handle);
+ command->hwqueue = handle;
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_queryadapterinfo *args)
@@ -2133,3 +2416,61 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
return ret;
}
+
+int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_submitcommandtohwqueue
+ *args)
+{
+ int ret = -EINVAL;
+ u32 cmd_size;
+ struct dxgkvmb_command_submitcommandtohwqueue *command;
+ u32 primaries_size = args->num_primaries * sizeof(struct d3dkmthandle);
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ cmd_size = sizeof(*command) + args->priv_drv_data_size + primaries_size;
+ ret = init_message(&msg, adapter, process, cmd_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ if (primaries_size) {
+ ret = copy_from_user(&command[1], args->written_primaries,
+ primaries_size);
+ if (ret) {
+ pr_err("%s failed to copy primaries handles", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+ if (args->priv_drv_data_size) {
+ ret = copy_from_user((char *)&command[1] + primaries_size,
+ args->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy primaries data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_SUBMITCOMMANDTOHWQUEUE,
+ process->host_handle);
+ command->args = *args;
+
+ 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)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 97f4d2471ca5..6e18002c9d25 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -897,6 +897,340 @@ static int dxgk_destroy_hwcontext(struct dxgprocess *process,
return -ENOTTY;
}
+static int
+dxgk_create_hwqueue(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_createhwqueue args;
+ struct dxgdevice *device = NULL;
+ struct dxgcontext *context = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct dxghwqueue *hwqueue = NULL;
+ int ret;
+ bool device_lock_acquired = false;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ args.context);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0)
+ goto cleanup;
+
+ device_lock_acquired = true;
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED);
+ context = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ args.context);
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED);
+
+ if (context == NULL) {
+ pr_err("Invalid context handle %x", args.context.v);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hwqueue = dxghwqueue_create(context);
+ if (hwqueue == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_create_hwqueue(process, adapter, &args,
+ inargs, hwqueue);
+
+cleanup:
+
+ if (ret < 0 && hwqueue)
+ dxghwqueue_destroy(process, hwqueue);
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device_lock_acquired)
+ dxgdevice_release_lock_shared(device);
+
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int dxgk_destroy_hwqueue(struct dxgprocess *process,
+ void *__user inargs)
+{
+ struct d3dkmt_destroyhwqueue args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxghwqueue *hwqueue = NULL;
+ struct d3dkmthandle device_handle = {};
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ hwqueue = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ args.queue);
+ if (hwqueue) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGHWQUEUE, args.queue);
+ hwqueue->handle.v = 0;
+ device_handle = hwqueue->device_handle;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ if (hwqueue == NULL) {
+ pr_err("invalid hwqueue handle: %x", args.queue.v);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ 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_destroy_hwqueue(process, adapter, args.queue);
+
+ dxghwqueue_destroy(process, hwqueue);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_create_paging_queue(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_createpagingqueue args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct dxgpagingqueue *pqueue = NULL;
+ int ret;
+ struct d3dkmthandle host_handle = {};
+ bool device_lock_acquired = false;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0)
+ goto cleanup;
+
+ device_lock_acquired = true;
+ adapter = device->adapter;
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ pqueue = dxgpagingqueue_create(device);
+ if (pqueue == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_create_paging_queue(process, device, &args, pqueue);
+ if (ret >= 0) {
+ host_handle = args.paging_queue;
+
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret < 0) {
+ pr_err("%s failed to copy input args", __func__);
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(&process->handle_table, pqueue,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ host_handle);
+ if (ret >= 0) {
+ pqueue->handle = host_handle;
+ ret = hmgrtable_assign_handle(&process->handle_table,
+ NULL,
+ HMGRENTRY_TYPE_MONITOREDFENCE,
+ args.sync_object);
+ if (ret >= 0)
+ pqueue->syncobj_handle = args.sync_object;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+ /* should not fail after this */
+ }
+
+cleanup:
+
+ if (ret < 0) {
+ if (pqueue)
+ dxgpagingqueue_destroy(pqueue);
+ if (host_handle.v)
+ dxgvmb_send_destroy_paging_queue(process,
+ adapter,
+ host_handle);
+ }
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device) {
+ if (device_lock_acquired)
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_destroy_paging_queue(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dddi_destroypagingqueue args;
+ struct dxgpagingqueue *paging_queue = NULL;
+ int ret;
+ struct d3dkmthandle device_handle = {};
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ paging_queue = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.paging_queue);
+ if (paging_queue) {
+ device_handle = paging_queue->device_handle;
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.paging_queue);
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_MONITOREDFENCE,
+ paging_queue->syncobj_handle);
+ paging_queue->syncobj_handle.v = 0;
+ paging_queue->handle.v = 0;
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ if (device_handle.v)
+ device = dxgprocess_device_by_handle(process, device_handle);
+ if (device == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ kref_put(&device->device_kref, dxgdevice_release);
+ device = NULL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_destroy_paging_queue(process, adapter,
+ args.paging_queue);
+
+ dxgpagingqueue_destroy(paging_queue);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device) {
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
static int
get_standard_alloc_priv_data(struct dxgdevice *device,
struct d3dkmt_createstandardallocation *alloc_info,
@@ -1619,6 +1953,290 @@ dxgk_destroy_allocation(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgk_submit_command(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_submitcommand args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.broadcast_context_count > D3DDDI_MAX_BROADCAST_CONTEXT ||
+ args.broadcast_context_count == 0) {
+ pr_err("invalid number of contexts");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ pr_err("invalid private data size");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.num_history_buffers > 1024) {
+ pr_err("invalid number of history buffers");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.num_primaries > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ pr_err("invalid number of primaries");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ args.broadcast_context[0]);
+ 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_submit_command(process, adapter, &args);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_submit_command_to_hwqueue(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_submitcommandtohwqueue args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ pr_err("invalid private data size");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.num_primaries > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ pr_err("invalid number of primaries");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ args.hwqueue);
+ 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_submit_command_hwqueue(process, adapter, &args);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_submit_signal_to_hwqueue(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_submitsignalsyncobjectstohwqueue args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct d3dkmthandle hwqueue = {};
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.hwqueue_count > D3DDDI_MAX_BROADCAST_CONTEXT ||
+ args.hwqueue_count == 0) {
+ pr_err("invalid hwqueue count");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.object_count > D3DDDI_MAX_OBJECT_SIGNALED ||
+ args.object_count == 0) {
+ pr_err("invalid number of syn cobject");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = copy_from_user(&hwqueue, args.hwqueues,
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy hwqueue handle", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ hwqueue);
+ 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.hwqueue_count, args.hwqueues,
+ args.object_count,
+ args.fence_values, NULL,
+ zerohandle);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_submitwaitforsyncobjectstohwqueue args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ int ret;
+ struct d3dkmthandle *objects = NULL;
+ u32 object_size;
+ u64 *fences = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.object_count > D3DDDI_MAX_OBJECT_WAITED_ON ||
+ args.object_count == 0) {
+ 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) {
+ pr_err("%s failed to copy objects", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ object_size = sizeof(u64) * args.object_count;
+ fences = vzalloc(object_size);
+ if (fences == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret = copy_from_user(fences, args.fence_values, object_size);
+ if (ret) {
+ pr_err("%s failed to copy fence values", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ args.hwqueue);
+ 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.hwqueue, args.object_count,
+ objects, fences, false);
+
+cleanup:
+
+ if (objects)
+ vfree(objects);
+ if (fences)
+ vfree(fences);
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
static int
dxgk_create_sync_object(struct dxgprocess *process, void *__user inargs)
{
@@ -3321,8 +3939,12 @@ void init_ioctls(void)
LX_DXDESTROYCONTEXT);
SET_IOCTL(/*0x6 */ dxgk_create_allocation,
LX_DXCREATEALLOCATION);
+ SET_IOCTL(/*0x7 */ dxgk_create_paging_queue,
+ LX_DXCREATEPAGINGQUEUE);
SET_IOCTL(/*0x9 */ dxgk_query_adapter_info,
LX_DXQUERYADAPTERINFO);
+ SET_IOCTL(/*0xf */ dxgk_submit_command,
+ LX_DXSUBMITCOMMAND);
SET_IOCTL(/*0x10 */ dxgk_create_sync_object,
LX_DXCREATESYNCHRONIZATIONOBJECT);
SET_IOCTL(/*0x11 */ dxgk_signal_sync_object,
@@ -3337,10 +3959,16 @@ void init_ioctls(void)
LX_DXCLOSEADAPTER);
SET_IOCTL(/*0x17 */ dxgk_create_hwcontext,
LX_DXCREATEHWCONTEXT);
+ SET_IOCTL(/*0x18 */ dxgk_create_hwqueue,
+ LX_DXCREATEHWQUEUE);
SET_IOCTL(/*0x19 */ dxgk_destroy_device,
LX_DXDESTROYDEVICE);
SET_IOCTL(/*0x1a */ dxgk_destroy_hwcontext,
LX_DXDESTROYHWCONTEXT);
+ SET_IOCTL(/*0x1b */ dxgk_destroy_hwqueue,
+ LX_DXDESTROYHWQUEUE);
+ SET_IOCTL(/*0x1c */ dxgk_destroy_paging_queue,
+ LX_DXDESTROYPAGINGQUEUE);
SET_IOCTL(/*0x1d */ dxgk_destroy_sync_object,
LX_DXDESTROYSYNCHRONIZATIONOBJECT);
SET_IOCTL(/*0x23 */ dxgk_get_shared_resource_adapter_luid,
@@ -3359,6 +3987,12 @@ void init_ioctls(void)
LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU);
SET_IOCTL(/*0x33 */ dxgk_signal_sync_object_gpu2,
LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2);
+ SET_IOCTL(/*0x34 */ dxgk_submit_command_to_hwqueue,
+ LX_DXSUBMITCOMMANDTOHWQUEUE);
+ SET_IOCTL(/*0x35 */ dxgk_submit_wait_to_hwqueue,
+ LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE);
+ SET_IOCTL(/*0x36 */ dxgk_submit_signal_to_hwqueue,
+ LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE);
SET_IOCTL(/*0x3a */ dxgk_wait_sync_object_cpu,
LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU);
SET_IOCTL(/*0x3b */ dxgk_wait_sync_object_gpu,
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
` (5 preceding siblings ...)
2022-01-12 19:55 ` [PATCH v1 7/9] drivers: hv: dxgkrnl: Implementation of submit command, paging and hardware queue Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-13 7:47 ` Greg KH
2022-01-12 19:55 ` [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE Iouri Tarassov
` (2 subsequent siblings)
9 siblings, 1 reply; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
Implement various WDDM IOCTLs.
- IOCTLs to handle GPU virtual addressing (VA):
LX_DXRESERVEGPUVIRTUALADDRESS (D3DKMTReserveGpuVertualAddress)
LX_DXFREEGPUVIRTUALADDRESS (D3DKMTFreeGpuVertualAddress)
LX_DXMAPGPUVIRTUALADDRESS (D3DKMTMapGpuVertualAddress)
LX_DXUPDATEGPUVIRTUALADDRESS (D3DKMTUpdateGpuVertualAddress)
WDDM supports a compute device to use GPU virtual addresses when
accessing allocation memory. A GPU VA could be reserved or mapped
to a GPU allocation. The video memory manager on the host updates
GPU page tables for the virtual addresses.
- IOCTLs to manage residency of GPU accessing allocations:
LX_DXMAKERESIDENT (D3DKMTMakeResident)
LX_DXEVICT (D3DKMTEvict)
An allocation is resident when GPU is setup to access it. The
current WDDM design does not support on demand GPU page faulting.
An allocation must be resident (be in the local device memory or
in non-pageable system memory) before GPU is allowed to access it.
- IOCTLs to offer/reclaim alloctions:
LX_DXOFFERALLOCATIONS {D3DKMTOfferAllocations)
LX_DXRECLAIMALLOCATIONS2 (D3DKMTReclaimAllocations)
When a user mode driver does not need an allocation, it can
"offer" it. This means that the allocation is not in use and it
local device memory could be reclaimed and given to another allocation.
When the allocation is again needed, the caller can "reclaim" the
allocations. If the allocation is still in the device local memory,
the reclaim operation succeeds. If not the called must restore the
content of the allocation before it can be used by the device.
- LX_DXESCAPE (D3DKMTEscape)
This IOCTL is used to send/receive private data between user mode
driver and kernel mode driver. This is an extension of the WDDM APIs.
- LX_DXGETDEVICESTATE (D3DKMTGetDeviceState)
The IOCTL is used to get the current execution state of the dxgdevice
object.
- LX_DXMARKDEVICEASERROR (D3DKMTMarkDeviceAsError)
The IOCTL is used to bring the dxgdevice object to the error state.
Subsequent calls to use the device object will fail.
- LX_DXQUERYSTATISTICS (D3DKMTQuerystatistics)
The IOCTL is used to query various statistics from the compute device
on the host.
- IOCTLs to deal with execution context priorities
LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY
LX_DXGETCONTEXTSCHEDULINGPRIORITY
LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY
LX_DXSETCONTEXTSCHEDULINGPRIORITY
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 2 +
drivers/hv/dxgkrnl/dxgvmbus.c | 1466 ++++++++++++++++++++++++++++---
drivers/hv/dxgkrnl/dxgvmbus.h | 15 +
drivers/hv/dxgkrnl/ioctl.c | 1524 ++++++++++++++++++++++++++++++++-
4 files changed, 2831 insertions(+), 176 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 9d2d55d9b509..73d917cb11d5 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -945,5 +945,7 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
int dxgvmb_send_query_statistics(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_querystatistics *args);
+int dxgvmb_send_share_object_with_host(struct dxgprocess *process,
+ struct d3dkmt_shareobjectwithhost *args);
#endif
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 67ff8bcbfb9a..773d8f364b34 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -859,6 +859,50 @@ int dxgvmb_send_destroy_sync_object(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_share_object_with_host(struct dxgprocess *process,
+ struct d3dkmt_shareobjectwithhost *args)
+{
+ struct dxgkvmb_command_shareobjectwithhost *command;
+ struct dxgkvmb_command_shareobjectwithhost_return result = {};
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, NULL, process, sizeof(*command));
+ if (ret)
+ return ret;
+ command = (void *)msg.msg;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+
+ command_vm_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST,
+ process->host_handle);
+ command->device_handle = args->device_handle;
+ command->object_handle = args->object_handle;
+
+ ret = dxgvmb_send_sync_msg(dxgglobal_get_dxgvmbuschannel(),
+ msg.hdr, msg.size, &result, sizeof(result));
+
+ dxgglobal_release_channel_lock();
+
+ if (ret || !NT_SUCCESS(result.status)) {
+ if (ret == 0)
+ ret = ntstatus2int(result.status);
+ pr_err("DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST failed: %d %x",
+ ret, result.status.v);
+ goto cleanup;
+ }
+ args->object_vail_nt_handle = result.vail_nt_handle;
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
/*
* Virtual GPU messages to the host
*/
@@ -1705,6 +1749,317 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_query_clock_calibration(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_queryclockcalibration
+ *args,
+ struct d3dkmt_queryclockcalibration
+ *__user inargs)
+{
+ struct dxgkvmb_command_queryclockcalibration *command;
+ struct dxgkvmb_command_queryclockcalibration_return result;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION,
+ process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0)
+ goto cleanup;
+ ret = copy_to_user(&inargs->clock_data, &result.clock_data,
+ sizeof(result.clock_data));
+ if (ret) {
+ pr_err("%s failed to copy clock data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = ntstatus2int(result.status);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_flushheaptransitions *args)
+{
+ struct dxgkvmb_command_flushheaptransitions *command;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_FLUSHHEAPTRANSITIONS,
+ process->host_handle);
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_queryallocationresidency
+ *args)
+{
+ int ret = -EINVAL;
+ struct dxgkvmb_command_queryallocationresidency *command = NULL;
+ u32 cmd_size = sizeof(*command);
+ u32 alloc_size = 0;
+ u32 result_allocation_size = 0;
+ struct dxgkvmb_command_queryallocationresidency_return *result = NULL;
+ u32 result_size = sizeof(*result);
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
+
+ if (args->allocation_count > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args->allocation_count) {
+ alloc_size = args->allocation_count *
+ sizeof(struct d3dkmthandle);
+ cmd_size += alloc_size;
+ result_allocation_size = args->allocation_count *
+ sizeof(args->residency_status[0]);
+ } else {
+ result_allocation_size = sizeof(args->residency_status[0]);
+ }
+ result_size += result_allocation_size;
+
+ ret = init_message_res(&msg, adapter, process, cmd_size, result_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ result = msg.res;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_QUERYALLOCATIONRESIDENCY,
+ process->host_handle);
+ command->args = *args;
+ if (alloc_size) {
+ ret = copy_from_user(&command[1], args->allocations,
+ alloc_size);
+ if (ret) {
+ pr_err("%s failed to copy alloc handles", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ result, msg.res_size);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(result->status);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(args->residency_status, &result[1],
+ result_allocation_size);
+ if (ret) {
+ pr_err("%s failed to copy residency status", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+ free_message((struct dxgvmbusmsg *)&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_escape(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_escape *args)
+{
+ int ret;
+ struct dxgkvmb_command_escape *command = NULL;
+ u32 cmd_size = sizeof(*command);
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ if (args->priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ cmd_size = cmd_size - sizeof(args->priv_drv_data[0]) +
+ args->priv_drv_data_size;
+
+ 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_ESCAPE,
+ process->host_handle);
+ command->adapter = args->adapter;
+ command->device = args->device;
+ command->type = args->type;
+ command->flags = args->flags;
+ command->priv_drv_data_size = args->priv_drv_data_size;
+ command->context = args->context;
+ if (args->priv_drv_data_size) {
+ ret = copy_from_user(command->priv_drv_data,
+ args->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy priv data", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ command->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret < 0)
+ goto cleanup;
+
+ if (args->priv_drv_data_size) {
+ ret = copy_to_user(args->priv_drv_data,
+ command->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ pr_err("%s failed to copy priv data", __func__);
+ ret = -EINVAL;
+ }
+ }
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_query_vidmem_info(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_queryvideomemoryinfo *args,
+ struct d3dkmt_queryvideomemoryinfo *__user
+ output)
+{
+ int ret;
+ struct dxgkvmb_command_queryvideomemoryinfo *command;
+ struct dxgkvmb_command_queryvideomemoryinfo_return result = { };
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ command_vgpu_to_host_init2(&command->hdr,
+ dxgk_vmbcommand_queryvideomemoryinfo,
+ process->host_handle);
+ command->adapter = args->adapter;
+ command->memory_segment_group = args->memory_segment_group;
+ command->physical_adapter_index = args->physical_adapter_index;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(&output->budget, &result.budget,
+ sizeof(output->budget));
+ if (ret) {
+ pr_err("%s failed to copy budget", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_to_user(&output->current_usage, &result.current_usage,
+ sizeof(output->current_usage));
+ if (ret) {
+ pr_err("%s failed to copy current usage", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_to_user(&output->current_reservation,
+ &result.current_reservation,
+ sizeof(output->current_reservation));
+ if (ret) {
+ pr_err("%s failed to copy reservation", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_to_user(&output->available_for_reservation,
+ &result.available_for_reservation,
+ sizeof(output->available_for_reservation));
+ if (ret) {
+ pr_err("%s failed to copy avail reservation", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_get_device_state(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_getdevicestate *args,
+ struct d3dkmt_getdevicestate *__user output)
+{
+ int ret;
+ struct dxgkvmb_command_getdevicestate *command;
+ struct dxgkvmb_command_getdevicestate_return result = { };
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ dxgk_vmbcommand_getdevicestate,
+ process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(result.status);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(output, &result.args, sizeof(result.args));
+ if (ret) {
+ pr_err("%s failed to copy output args", __func__);
+ ret = -EINVAL;
+ }
+
+ if (args->state_type == _D3DKMT_DEVICESTATE_EXECUTION)
+ args->execution_state = result.args.execution_state;
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
int dxgvmb_send_open_resource(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmthandle device,
@@ -1844,14 +2199,112 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
return ret;
}
-int dxgvmb_send_submit_command(struct dxgprocess *process,
- struct dxgadapter *adapter,
- struct d3dkmt_submitcommand *args)
+int dxgvmb_send_make_resident(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dddi_makeresident *args)
{
int ret;
u32 cmd_size;
- struct dxgkvmb_command_submitcommand *command;
- u32 hbufsize = args->num_history_buffers * sizeof(struct d3dkmthandle);
+ struct dxgkvmb_command_makeresident_return result = { };
+ struct dxgkvmb_command_makeresident *command = NULL;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ cmd_size = (args->alloc_count - 1) * sizeof(struct d3dkmthandle) +
+ sizeof(struct dxgkvmb_command_makeresident);
+
+ ret = init_message(&msg, adapter, process, cmd_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ ret = copy_from_user(command->allocations, args->allocation_list,
+ args->alloc_count *
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy alloc handles", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_MAKERESIDENT,
+ process->host_handle);
+ command->alloc_count = args->alloc_count;
+ command->paging_queue = args->paging_queue;
+ command->flags = args->flags;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0) {
+ pr_err("send_make_resident failed %x", ret);
+ goto cleanup;
+ }
+
+ args->paging_fence_value = result.paging_fence_value;
+ args->num_bytes_to_trim = result.num_bytes_to_trim;
+ ret = ntstatus2int(result.status);
+
+cleanup:
+
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_evict(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_evict *args)
+{
+ int ret;
+ u32 cmd_size;
+ struct dxgkvmb_command_evict_return result = { };
+ struct dxgkvmb_command_evict *command = NULL;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ cmd_size = (args->alloc_count - 1) * sizeof(struct d3dkmthandle) +
+ sizeof(struct dxgkvmb_command_evict);
+ ret = init_message(&msg, adapter, process, cmd_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ ret = copy_from_user(command->allocations, args->allocations,
+ args->alloc_count *
+ sizeof(struct d3dkmthandle));
+ if (ret) {
+ pr_err("%s failed to copy alloc handles", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_EVICT, process->host_handle);
+ command->alloc_count = args->alloc_count;
+ command->device = args->device;
+ command->flags = args->flags;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0) {
+ pr_err("send_evict failed %x", ret);
+ goto cleanup;
+ }
+ args->num_bytes_to_trim = result.num_bytes_to_trim;
+
+cleanup:
+
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_submit_command(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_submitcommand *args)
+{
+ int ret;
+ u32 cmd_size;
+ struct dxgkvmb_command_submitcommand *command;
+ u32 hbufsize = args->num_history_buffers * sizeof(struct d3dkmthandle);
struct dxgvmbusmsg msg = {.hdr = NULL};
cmd_size = sizeof(struct dxgkvmb_command_submitcommand) +
@@ -1898,6 +2351,156 @@ int dxgvmb_send_submit_command(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_map_gpu_va(struct dxgprocess *process,
+ struct d3dkmthandle device,
+ struct dxgadapter *adapter,
+ struct d3dddi_mapgpuvirtualaddress *args)
+{
+ struct dxgkvmb_command_mapgpuvirtualaddress *command;
+ struct dxgkvmb_command_mapgpuvirtualaddress_return result;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_MAPGPUVIRTUALADDRESS,
+ process->host_handle);
+ command->args = *args;
+ command->device = device;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result,
+ sizeof(result));
+ if (ret < 0)
+ goto cleanup;
+ args->virtual_address = result.virtual_address;
+ args->paging_fence_value = result.paging_fence_value;
+ ret = ntstatus2int(result.status);
+
+cleanup:
+
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_reserve_gpu_va(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dddi_reservegpuvirtualaddress *args)
+{
+ struct dxgkvmb_command_reservegpuvirtualaddress *command;
+ struct dxgkvmb_command_reservegpuvirtualaddress_return result;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_RESERVEGPUVIRTUALADDRESS,
+ process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result,
+ sizeof(result));
+ args->virtual_address = result.virtual_address;
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_free_gpu_va(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_freegpuvirtualaddress *args)
+{
+ struct dxgkvmb_command_freegpuvirtualaddress *command;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_FREEGPUVIRTUALADDRESS,
+ process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_update_gpu_va(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_updategpuvirtualaddress *args)
+{
+ struct dxgkvmb_command_updategpuvirtualaddress *command;
+ u32 cmd_size;
+ u32 op_size;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ if (args->num_operations == 0 ||
+ (DXG_MAX_VM_BUS_PACKET_SIZE /
+ sizeof(struct d3dddi_updategpuvirtualaddress_operation)) <
+ args->num_operations) {
+ ret = -EINVAL;
+ pr_err("Invalid number of operations: %d",
+ args->num_operations);
+ goto cleanup;
+ }
+
+ op_size = args->num_operations *
+ sizeof(struct d3dddi_updategpuvirtualaddress_operation);
+ cmd_size = sizeof(struct dxgkvmb_command_updategpuvirtualaddress) +
+ op_size - sizeof(args->operations[0]);
+
+ 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_UPDATEGPUVIRTUALADDRESS,
+ process->host_handle);
+ command->fence_value = args->fence_value;
+ command->device = args->device;
+ command->context = args->context;
+ command->fence_object = args->fence_object;
+ command->num_operations = args->num_operations;
+ command->flags = args->flags.value;
+ ret = copy_from_user(command->operations, args->operations,
+ op_size);
+ if (ret) {
+ pr_err("%s failed to copy operations", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
static void set_result(struct d3dkmt_createsynchronizationobject2 *args,
u64 fence_gpu_va, u8 *va)
{
@@ -1978,98 +2581,593 @@ dxgvmb_send_create_sync_object(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ 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};
+
+ 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) {
+ pr_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) {
+ pr_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) {
+ pr_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)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, 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) {
+ pr_err("%s failed to copy objects", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ current_pos += object_size;
+ ret = copy_from_user(current_pos, args->fence_values, fence_size);
+ if (ret) {
+ pr_err("%s failed to copy fences", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, 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};
+
+ 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)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_lock2(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_lock2 *args,
+ struct d3dkmt_lock2 *__user outargs)
+{
+ int ret;
+ struct dxgkvmb_command_lock2 *command;
+ struct dxgkvmb_command_lock2_return result = { };
+ struct dxgallocation *alloc = NULL;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_LOCK2, process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(result.status);
+ if (ret < 0)
+ goto cleanup;
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ alloc = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ args->allocation);
+ if (alloc == NULL) {
+ pr_err("%s invalid alloc", __func__);
+ ret = -EINVAL;
+ } else {
+ if (alloc->cpu_address) {
+ args->data = alloc->cpu_address;
+ if (alloc->cpu_address_mapped)
+ alloc->cpu_address_refcount++;
+ } else {
+ u64 offset = (u64)result.cpu_visible_buffer_offset;
+
+ args->data = dxg_map_iospace(offset,
+ alloc->num_pages << PAGE_SHIFT,
+ PROT_READ | PROT_WRITE, alloc->cached);
+ if (args->data) {
+ alloc->cpu_address_refcount = 1;
+ alloc->cpu_address_mapped = true;
+ alloc->cpu_address = args->data;
+ }
+ }
+ if (args->data == NULL) {
+ ret = -ENOMEM;
+ } else {
+ ret = copy_to_user(&outargs->data, &args->data,
+ sizeof(args->data));
+ if (ret) {
+ pr_err("%s failed to copy data", __func__);
+ ret = -EINVAL;
+ alloc->cpu_address_refcount--;
+ if (alloc->cpu_address_refcount == 0) {
+ dxg_unmap_iospace(alloc->cpu_address,
+ alloc->num_pages << PAGE_SHIFT);
+ alloc->cpu_address_mapped = false;
+ alloc->cpu_address = NULL;
+ }
+ }
+ }
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_unlock2(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_unlock2 *args)
+{
+ int ret;
+ struct dxgkvmb_command_unlock2 *command;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_UNLOCK2,
+ process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_update_alloc_property(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dddi_updateallocproperty *args,
+ struct d3dddi_updateallocproperty *__user
+ inargs)
+{
+ int ret;
+ int ret1;
+ struct dxgkvmb_command_updateallocationproperty *command;
+ struct dxgkvmb_command_updateallocationproperty_return result = { };
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_UPDATEALLOCATIONPROPERTY,
+ process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+
+ if (ret < 0)
+ goto cleanup;
+ ret = ntstatus2int(result.status);
+ /* STATUS_PENING is a success code > 0 */
+ if (ret == STATUS_PENDING) {
+ ret1 = copy_to_user(&inargs->paging_fence_value,
+ &result.paging_fence_value,
+ sizeof(u64));
+ if (ret1) {
+ pr_err("%s failed to copy paging fence", __func__);
+ ret = -EINVAL;
+ }
+ }
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_mark_device_as_error(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_markdeviceaserror *args)
+{
+ struct dxgkvmb_command_markdeviceaserror *command;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_MARKDEVICEASERROR,
+ process->host_handle);
+ command->args = *args;
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_set_allocation_priority(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_setallocationpriority *args)
+{
+ u32 cmd_size = sizeof(struct dxgkvmb_command_setallocationpriority);
+ u32 alloc_size = 0;
+ u32 priority_size = 0;
+ struct dxgkvmb_command_setallocationpriority *command;
+ int ret;
+ struct d3dkmthandle *allocations;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ if (args->allocation_count > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (args->resource.v) {
+ priority_size = sizeof(u32);
+ if (args->allocation_count != 0) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ } else {
+ if (args->allocation_count == 0) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ alloc_size = args->allocation_count *
+ sizeof(struct d3dkmthandle);
+ cmd_size += alloc_size;
+ priority_size = sizeof(u32) * args->allocation_count;
+ }
+ cmd_size += priority_size;
+
+ 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_SETALLOCATIONPRIORITY,
+ process->host_handle);
+ command->device = args->device;
+ command->allocation_count = args->allocation_count;
+ command->resource = args->resource;
+ allocations = (struct d3dkmthandle *) &command[1];
+ ret = copy_from_user(allocations, args->allocation_list,
+ alloc_size);
+ if (ret) {
+ pr_err("%s failed to copy alloc handle", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ ret = copy_from_user((u8 *) allocations + alloc_size,
+ args->priorities, priority_size);
+ if (ret) {
+ pr_err("%s failed to copy alloc priority", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_get_allocation_priority(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_getallocationpriority *args)
+{
+ u32 cmd_size = sizeof(struct dxgkvmb_command_getallocationpriority);
+ u32 result_size;
+ u32 alloc_size = 0;
+ u32 priority_size = 0;
+ struct dxgkvmb_command_getallocationpriority *command;
+ struct dxgkvmb_command_getallocationpriority_return *result;
+ int ret;
+ struct d3dkmthandle *allocations;
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
+
+ if (args->allocation_count > DXG_MAX_VM_BUS_PACKET_SIZE) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (args->resource.v) {
+ priority_size = sizeof(u32);
+ if (args->allocation_count != 0) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ } else {
+ if (args->allocation_count == 0) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ alloc_size = args->allocation_count *
+ sizeof(struct d3dkmthandle);
+ cmd_size += alloc_size;
+ priority_size = sizeof(u32) * args->allocation_count;
+ }
+ result_size = sizeof(*result) + priority_size;
+
+ ret = init_message_res(&msg, adapter, process, cmd_size, result_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ result = msg.res;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_GETALLOCATIONPRIORITY,
+ process->host_handle);
+ command->device = args->device;
+ command->allocation_count = args->allocation_count;
+ command->resource = args->resource;
+ allocations = (struct d3dkmthandle *) &command[1];
+ ret = copy_from_user(allocations, args->allocation_list,
+ alloc_size);
+ if (ret) {
+ pr_err("%s failed to copy alloc handles", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr,
+ msg.size + msg.res_size,
+ result, msg.res_size);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = ntstatus2int(result->status);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(args->priorities,
+ (u8 *) result + sizeof(*result),
+ priority_size);
+ if (ret) {
+ pr_err("%s failed to copy priorities", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+ free_message((struct dxgvmbusmsg *)&msg, process);
if (ret)
dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
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 dxgvmb_send_set_context_sch_priority(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle context,
+ int priority,
+ bool in_process)
{
+ struct dxgkvmb_command_setcontextschedulingpriority2 *command;
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};
- if (context.v)
- cmd_size += sizeof(struct d3dkmthandle);
-
- ret = init_message(&msg, adapter, process, cmd_size);
+ ret = init_message(&msg, adapter, process, sizeof(*command));
if (ret)
goto cleanup;
command = (void *)msg.msg;
command_vgpu_to_host_init2(&command->hdr,
- DXGK_VMBCOMMAND_SIGNALSYNCOBJECT,
+ DXGK_VMBCOMMAND_SETCONTEXTSCHEDULINGPRIORITY,
process->host_handle);
+ command->context = context;
+ command->priority = priority;
+ command->in_process = in_process;
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
- 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) {
- pr_err("Failed to read objects %p %d",
- objects, object_size);
- ret = -EINVAL;
+int dxgvmb_send_get_context_sch_priority(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle context,
+ int *priority,
+ bool in_process)
+{
+ struct dxgkvmb_command_getcontextschedulingpriority *command;
+ struct dxgkvmb_command_getcontextschedulingpriority_return result = { };
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
+ if (ret)
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) {
- pr_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) {
- pr_err("Failed to read fences %p %d",
- fences, fence_size);
- ret = -EINVAL;
- goto cleanup;
- }
- }
+ command = (void *)msg.msg;
- 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);
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_GETCONTEXTSCHEDULINGPRIORITY,
+ process->host_handle);
+ command->context = context;
+ command->in_process = in_process;
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ &result, sizeof(result));
+ if (ret >= 0) {
+ ret = ntstatus2int(result.status);
+ *priority = result.priority;
}
-
cleanup:
free_message(&msg, process);
if (ret)
@@ -2077,19 +3175,15 @@ int dxgvmb_send_signal_sync_object(struct dxgprocess *process,
return ret;
}
-int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
- struct dxgadapter *adapter,
- struct
- d3dkmt_waitforsynchronizationobjectfromcpu
- *args,
- u64 cpu_event)
+int dxgvmb_send_offer_allocations(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_offerallocations *args)
{
+ struct dxgkvmb_command_offerallocations *command;
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;
+ u32 alloc_size = sizeof(struct d3dkmthandle) * args->allocation_count;
+ u32 cmd_size = sizeof(struct dxgkvmb_command_offerallocations) +
+ alloc_size - sizeof(struct d3dkmthandle);
struct dxgvmbusmsg msg = {.hdr = NULL};
ret = init_message(&msg, adapter, process, cmd_size);
@@ -2098,23 +3192,22 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
command = (void *)msg.msg;
command_vgpu_to_host_init2(&command->hdr,
- DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMCPU,
+ DXGK_VMBCOMMAND_OFFERALLOCATIONS,
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) {
- pr_err("%s failed to copy objects", __func__);
- ret = -EINVAL;
- goto cleanup;
+ command->priority = args->priority;
+ command->device = args->device;
+ command->allocation_count = args->allocation_count;
+ if (args->resources) {
+ command->resources = true;
+ ret = copy_from_user(command->allocations, args->resources,
+ alloc_size);
+ } else {
+ ret = copy_from_user(command->allocations,
+ args->allocations, alloc_size);
}
- current_pos += object_size;
- ret = copy_from_user(current_pos, args->fence_values, fence_size);
if (ret) {
- pr_err("%s failed to copy fences", __func__);
+ pr_err("%s failed to copy input handles", __func__);
ret = -EINVAL;
goto cleanup;
}
@@ -2128,51 +3221,105 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
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 dxgvmb_send_reclaim_allocations(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle device,
+ struct d3dkmt_reclaimallocations2 *args,
+ u64 __user *paging_fence_value)
{
+ struct dxgkvmb_command_reclaimallocations *command;
+ struct dxgkvmb_command_reclaimallocations_return *result;
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};
+ u32 alloc_size = sizeof(struct d3dkmthandle) * args->allocation_count;
+ u32 cmd_size = sizeof(struct dxgkvmb_command_reclaimallocations) +
+ alloc_size - sizeof(struct d3dkmthandle);
+ u32 result_size = sizeof(*result);
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
- if (object_count == 0 || object_count > D3DDDI_MAX_OBJECT_WAITED_ON) {
+ if (args->results)
+ result_size += (args->allocation_count - 1) *
+ sizeof(enum d3dddi_reclaim_result);
+
+ ret = init_message_res(&msg, adapter, process, cmd_size, result_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ result = msg.res;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_RECLAIMALLOCATIONS,
+ process->host_handle);
+ command->device = device;
+ command->paging_queue = args->paging_queue;
+ command->allocation_count = args->allocation_count;
+ command->write_results = args->results != NULL;
+ if (args->resources) {
+ command->resources = true;
+ ret = copy_from_user(command->allocations, args->resources,
+ alloc_size);
+ } else {
+ ret = copy_from_user(command->allocations,
+ args->allocations, alloc_size);
+ }
+ if (ret) {
+ pr_err("%s failed to copy input handles", __func__);
ret = -EINVAL;
goto cleanup;
}
- ret = init_message(&msg, adapter, process, cmd_size);
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ result, msg.res_size);
+ if (ret < 0)
+ goto cleanup;
+ ret = copy_to_user(paging_fence_value,
+ &result->paging_fence_value, sizeof(u64));
+ if (ret) {
+ pr_err("%s failed to copy paging fence", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = ntstatus2int(result->status);
+ if (NT_SUCCESS(result->status) && args->results) {
+ ret = copy_to_user(args->results, result->discarded,
+ sizeof(result->discarded[0]) *
+ args->allocation_count);
+ if (ret) {
+ pr_err("%s failed to copy results", __func__);
+ ret = -EINVAL;
+ }
+ }
+
+cleanup:
+ free_message((struct dxgvmbusmsg *)&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
+
+int dxgvmb_send_change_vidmem_reservation(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmthandle other_process,
+ struct
+ d3dkmt_changevideomemoryreservation
+ *args)
+{
+ struct dxgkvmb_command_changevideomemoryreservation *command;
+ int ret;
+ struct dxgvmbusmsg msg = {.hdr = NULL};
+
+ ret = init_message(&msg, adapter, process, sizeof(*command));
if (ret)
goto cleanup;
command = (void *)msg.msg;
command_vgpu_to_host_init2(&command->hdr,
- DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMGPU,
+ DXGK_VMBCOMMAND_CHANGEVIDEOMEMORYRESERVATION,
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);
- }
+ command->args = *args;
+ command->args.process = other_process.v;
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
free_message(&msg, process);
if (ret)
@@ -2259,37 +3406,43 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
ret = copy_to_user(&inargs->queue, &command->hwqueue,
sizeof(struct d3dkmthandle));
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy hwqueue handle", __func__);
+ ret = -EINVAL;
goto cleanup;
}
ret = copy_to_user(&inargs->queue_progress_fence,
&command->hwqueue_progress_fence,
sizeof(struct d3dkmthandle));
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to progress fence", __func__);
+ ret = -EINVAL;
goto cleanup;
}
ret = copy_to_user(&inargs->queue_progress_fence_cpu_va,
&hwqueue->progress_fence_mapped_address,
sizeof(inargs->queue_progress_fence_cpu_va));
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy fence cpu va", __func__);
+ ret = -EINVAL;
goto cleanup;
}
ret = copy_to_user(&inargs->queue_progress_fence_gpu_va,
&command->hwqueue_progress_fence_gpuva,
sizeof(u64));
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy fence gpu va", __func__);
+ ret = -EINVAL;
goto cleanup;
}
if (args->priv_drv_data_size) {
ret = copy_to_user(args->priv_drv_data,
command->priv_drv_data,
args->priv_drv_data_size);
- if (ret < 0)
+ if (ret) {
pr_err("%s failed to copy private data", __func__);
+ ret = -EINVAL;
+ }
}
cleanup:
@@ -2474,3 +3627,38 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_query_statistics(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_querystatistics *args)
+{
+ struct dxgkvmb_command_querystatistics *command;
+ struct dxgkvmb_command_querystatistics_return *result;
+ int ret;
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
+
+ ret = init_message_res(&msg, adapter, process, sizeof(*command),
+ sizeof(*result));
+ if (ret)
+ goto cleanup;
+ command = msg.msg;
+ result = msg.res;
+
+ command_vgpu_to_host_init2(&command->hdr,
+ DXGK_VMBCOMMAND_QUERYSTATISTICS,
+ process->host_handle);
+ command->args = *args;
+
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ result, msg.res_size);
+ if (ret < 0)
+ goto cleanup;
+
+ args->result = result->result;
+ ret = ntstatus2int(result->status);
+
+cleanup:
+ free_message((struct dxgvmbusmsg *)&msg, process);
+ if (ret)
+ dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
+ return ret;
+}
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index c166a2820052..a19ac804a320 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -63,6 +63,7 @@ enum dxgkvmb_commandtype_global {
DXGK_VMBCOMMAND_QUERYETWSESSION = 1009,
DXGK_VMBCOMMAND_SETIOSPACEREGION = 1010,
DXGK_VMBCOMMAND_COMPLETETRANSACTION = 1011,
+ DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST = 1021,
DXGK_VMBCOMMAND_INVALID_VM_TO_HOST
};
@@ -520,6 +521,7 @@ struct dxgkvmb_command_querystatistics {
struct dxgkvmb_command_querystatistics_return {
struct ntstatus status;
+ u32 reserved;
struct d3dkmt_querystatistics_result result;
};
@@ -847,6 +849,19 @@ struct dxgkvmb_command_getdevicestate_return {
struct ntstatus status;
};
+struct dxgkvmb_command_shareobjectwithhost {
+ struct dxgkvmb_command_vm_to_host hdr;
+ struct d3dkmthandle device_handle;
+ struct d3dkmthandle object_handle;
+ u64 reserved;
+};
+
+struct dxgkvmb_command_shareobjectwithhost_return {
+ struct ntstatus status;
+ u32 alignment;
+ u64 vail_nt_handle;
+};
+
/*
* Helper functions
*/
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 6e18002c9d25..9770fabf163e 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -156,6 +156,66 @@ static int dxgk_open_adapter_from_luid(struct dxgprocess *process,
return ret;
}
+static int dxgk_query_statistics(struct dxgprocess *process,
+ void __user *inargs)
+{
+ struct d3dkmt_querystatistics *args;
+ int ret;
+ struct dxgadapter *entry;
+ struct dxgadapter *adapter = NULL;
+ struct winluid tmp;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ args = vzalloc(sizeof(struct d3dkmt_querystatistics));
+ if (args == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = copy_from_user(args, inargs, sizeof(*args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED);
+ list_for_each_entry(entry, &dxgglobal->adapter_list_head,
+ adapter_list_entry) {
+ if (dxgadapter_acquire_lock_shared(entry) == 0) {
+ if (*(u64 *) &entry->luid ==
+ *(u64 *) &args->adapter_luid) {
+ adapter = entry;
+ break;
+ }
+ dxgadapter_release_lock_shared(entry);
+ }
+ }
+ dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED);
+ if (adapter) {
+ tmp = args->adapter_luid;
+ args->adapter_luid = adapter->host_adapter_luid;
+ ret = dxgvmb_send_query_statistics(process, adapter, args);
+ if (ret >= 0) {
+ args->adapter_luid = tmp;
+ ret = copy_to_user(inargs, args, sizeof(*args));
+ if (ret) {
+ pr_err("%s failed to copy args", __func__);
+ ret = -EINVAL;
+ }
+ }
+ dxgadapter_release_lock_shared(adapter);
+ }
+
+cleanup:
+ if (args)
+ vfree(args);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
static int
dxgkp_enum_adapters(struct dxgprocess *process,
union d3dkmt_enumadapters_filter filter,
@@ -1105,8 +1165,9 @@ dxgk_create_paging_queue(struct dxgprocess *process, void *__user inargs)
host_handle = args.paging_queue;
ret = copy_to_user(inargs, &args, sizeof(args));
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
goto cleanup;
}
@@ -1953,6 +2014,261 @@ dxgk_destroy_allocation(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgk_make_resident(struct dxgprocess *process, void *__user inargs)
+{
+ int ret, ret2;
+ struct d3dddi_makeresident args;
+ struct d3dddi_makeresident *input = inargs;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.alloc_count > D3DKMT_MAKERESIDENT_ALLOC_MAX ||
+ args.alloc_count == 0) {
+ pr_err("invalid number of allocations");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (args.paging_queue.v == 0) {
+ pr_err("paging queue is missing");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.paging_queue);
+ 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_make_resident(process, adapter, &args);
+ if (ret < 0)
+ goto cleanup;
+ /* STATUS_PENING is a success code > 0. It is returned to user mode */
+ if (!(ret == STATUS_PENDING || ret == 0)) {
+ pr_err("%s Unexpected error %x", __func__, ret);
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->paging_fence_value,
+ &args.paging_fence_value, sizeof(u64));
+ if (ret2) {
+ pr_err("%s failed to copy paging fence", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->num_bytes_to_trim,
+ &args.num_bytes_to_trim, sizeof(u64));
+ if (ret2) {
+ pr_err("%s failed to copy bytes to trim", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+
+ return ret;
+}
+
+static int
+dxgk_evict(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_evict args;
+ struct d3dkmt_evict *input = inargs;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.alloc_count > D3DKMT_MAKERESIDENT_ALLOC_MAX ||
+ args.alloc_count == 0) {
+ pr_err("invalid number of allocations");
+ 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_evict(process, adapter, &args);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(&input->num_bytes_to_trim,
+ &args.num_bytes_to_trim, sizeof(u64));
+ if (ret) {
+ pr_err("%s failed to copy bytes to trim to user", __func__);
+ ret = -EINVAL;
+ }
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_offer_allocations(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_offerallocations args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.allocation_count > D3DKMT_MAKERESIDENT_ALLOC_MAX ||
+ args.allocation_count == 0) {
+ pr_err("invalid number of allocations");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if ((args.resources == NULL) == (args.allocations == NULL)) {
+ pr_err("invalid pointer to resources/allocations");
+ 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_offer_allocations(process, adapter, &args);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_reclaim_allocations(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_reclaimallocations2 args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct d3dkmt_reclaimallocations2 * __user in_args = inargs;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.allocation_count > D3DKMT_MAKERESIDENT_ALLOC_MAX ||
+ args.allocation_count == 0) {
+ pr_err("invalid number of allocations");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if ((args.resources == NULL) == (args.allocations == NULL)) {
+ pr_err("invalid pointer to resources/allocations");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.paging_queue);
+ 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_reclaim_allocations(process, adapter,
+ device->handle, &args,
+ &in_args->paging_fence_value);
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
static int
dxgk_submit_command(struct dxgprocess *process, void *__user inargs)
{
@@ -2237,6 +2553,228 @@ dxgk_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgk_map_gpu_va(struct dxgprocess *process, void *__user inargs)
+{
+ int ret, ret2;
+ struct d3dddi_mapgpuvirtualaddress args;
+ struct d3dddi_mapgpuvirtualaddress *input = inargs;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.paging_queue);
+ 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_map_gpu_va(process, zerohandle, adapter, &args);
+ if (ret < 0)
+ goto cleanup;
+ /* STATUS_PENING is a success code > 0. It is returned to user mode */
+ if (!(ret == STATUS_PENDING || ret == 0)) {
+ pr_err("%s Unexpected error %x", __func__, ret);
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->paging_fence_value,
+ &args.paging_fence_value, sizeof(u64));
+ if (ret2) {
+ pr_err("%s failed to copy paging fence to user", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->virtual_address, &args.virtual_address,
+ sizeof(args.virtual_address));
+ if (ret2) {
+ pr_err("%s failed to copy va to user", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_reserve_gpu_va(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dddi_reservegpuvirtualaddress args;
+ struct d3dddi_reservegpuvirtualaddress *input = inargs;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.adapter);
+ if (device == NULL) {
+ pr_err("invalid adapter or paging queue: 0x%x",
+ args.adapter.v);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ adapter = device->adapter;
+ kref_get(&adapter->adapter_kref);
+ kref_put(&device->device_kref, dxgdevice_release);
+ } else {
+ args.adapter = adapter->host_handle;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_reserve_gpu_va(process, adapter, &args);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(&input->virtual_address, &args.virtual_address,
+ sizeof(args.virtual_address));
+ if (ret) {
+ pr_err("%s failed to copy VA to user", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (adapter) {
+ dxgadapter_release_lock_shared(adapter);
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ }
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_free_gpu_va(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_freegpuvirtualaddress args;
+ struct dxgadapter *adapter = NULL;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ args.adapter = adapter->host_handle;
+ ret = dxgvmb_send_free_gpu_va(process, adapter, &args);
+
+cleanup:
+
+ if (adapter) {
+ dxgadapter_release_lock_shared(adapter);
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ }
+
+ return ret;
+}
+
+static int
+dxgk_update_gpu_va(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_updategpuvirtualaddress args;
+ struct d3dkmt_updategpuvirtualaddress *input = inargs;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ 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_update_gpu_va(process, adapter, &args);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = copy_to_user(&input->fence_value, &args.fence_value,
+ sizeof(args.fence_value));
+ if (ret) {
+ pr_err("%s failed to copy fence value to user", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ return ret;
+}
+
static int
dxgk_create_sync_object(struct dxgprocess *process, void *__user inargs)
{
@@ -2512,8 +3050,9 @@ dxgk_open_sync_object_nt(struct dxgprocess *process, void *__user inargs)
goto cleanup;
ret = copy_to_user(inargs, &args, sizeof(args));
- if (ret >= 0)
+ if (ret == 0)
goto success;
+ ret = -EINVAL;
pr_err("%s failed to copy output args", __func__);
cleanup:
@@ -3205,41 +3744,849 @@ dxgk_wait_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
}
static int
-dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj,
- struct dxgprocess *process,
- struct d3dkmthandle objecthandle)
+dxgk_lock2(struct dxgprocess *process, void *__user inargs)
{
- int ret = 0;
+ struct d3dkmt_lock2 args;
+ struct d3dkmt_lock2 *__user result = inargs;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxgallocation *alloc = NULL;
- mutex_lock(&syncobj->fd_mutex);
- if (syncobj->host_shared_handle_nt_reference == 0) {
- ret = dxgvmb_send_create_nt_shared_object(process,
- objecthandle,
- &syncobj->host_shared_handle_nt);
- if (ret < 0)
- goto cleanup;
- dev_dbg(dxgglobaldev, "Host_shared_handle_ht: %x",
- syncobj->host_shared_handle_nt.v);
- kref_get(&syncobj->ssyncobj_kref);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
}
- syncobj->host_shared_handle_nt_reference++;
+
+ args.data = NULL;
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ alloc = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ args.allocation);
+ if (alloc == NULL) {
+ ret = -EINVAL;
+ } else {
+ if (alloc->cpu_address) {
+ ret = copy_to_user(&result->data,
+ &alloc->cpu_address,
+ sizeof(args.data));
+ if (ret == 0) {
+ args.data = alloc->cpu_address;
+ if (alloc->cpu_address_mapped)
+ alloc->cpu_address_refcount++;
+ } else {
+ pr_err("%s Failed to copy cpu address",
+ __func__);
+ ret = -EINVAL;
+ }
+ }
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+ if (ret < 0)
+ goto cleanup;
+ if (args.data)
+ goto success;
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ 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_lock2(process, adapter, &args, result);
+
cleanup:
- mutex_unlock(&syncobj->fd_mutex);
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+success:
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
return ret;
}
static int
-dxgsharedresource_get_host_nt_handle(struct dxgsharedresource *resource,
- struct dxgprocess *process,
- struct d3dkmthandle objecthandle)
+dxgk_unlock2(struct dxgprocess *process, void *__user inargs)
{
- int ret = 0;
+ struct d3dkmt_unlock2 args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxgallocation *alloc = NULL;
+ bool done = false;
- mutex_lock(&resource->fd_mutex);
- if (resource->host_shared_handle_nt_reference == 0) {
- ret = dxgvmb_send_create_nt_shared_object(process,
- objecthandle,
- &resource->host_shared_handle_nt);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ alloc = hmgrtable_get_object_by_type(&process->handle_table,
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ args.allocation);
+ if (alloc == NULL) {
+ ret = -EINVAL;
+ } else {
+ if (alloc->cpu_address == NULL) {
+ pr_err("Allocation is not locked: %p", alloc);
+ ret = -EINVAL;
+ } else if (alloc->cpu_address_mapped) {
+ if (alloc->cpu_address_refcount > 0) {
+ alloc->cpu_address_refcount--;
+ if (alloc->cpu_address_refcount != 0) {
+ done = true;
+ } else {
+ dxg_unmap_iospace(alloc->cpu_address,
+ alloc->num_pages << PAGE_SHIFT);
+ alloc->cpu_address_mapped = false;
+ alloc->cpu_address = NULL;
+ }
+ } else {
+ pr_err("Invalid cpu access refcount");
+ done = true;
+ }
+ }
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+ if (done)
+ goto success;
+ if (ret < 0)
+ goto cleanup;
+
+ /*
+ * The call acquires reference on the device. It is safe to access the
+ * adapter, because the device holds reference on it.
+ */
+ 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_unlock2(process, adapter, &args);
+
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+success:
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_update_alloc_property(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dddi_updateallocproperty args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.paging_queue);
+ 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_update_alloc_property(process, adapter,
+ &args, inargs);
+
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_mark_device_as_error(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_markdeviceaserror args;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ int ret;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ 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;
+ }
+ device->execution_state = _D3DKMT_DEVICEEXECUTION_RESET;
+ ret = dxgvmb_send_mark_device_as_error(process, adapter, &args);
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_query_alloc_residency(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_queryallocationresidency args;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if ((args.allocation_count == 0) == (args.resource.v == 0)) {
+ 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_query_alloc_residency(process, adapter, &args);
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_set_allocation_priority(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_setallocationpriority args;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ 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_set_allocation_priority(process, adapter, &args);
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_get_allocation_priority(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_getallocationpriority args;
+ struct dxgadapter *adapter = NULL;
+ struct dxgdevice *device = NULL;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ 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_get_allocation_priority(process, adapter, &args);
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+set_context_scheduling_priority(struct dxgprocess *process,
+ struct d3dkmthandle hcontext,
+ int priority, bool in_process)
+{
+ int ret = 0;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ hcontext);
+ 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_set_context_sch_priority(process, adapter,
+ hcontext, priority,
+ in_process);
+ if (ret < 0)
+ pr_err("send_set_context_scheduling_priority failed");
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ return ret;
+}
+
+static int
+dxgk_set_context_scheduling_priority(struct dxgprocess *process,
+ void *__user inargs)
+{
+ struct d3dkmt_setcontextschedulingpriority args;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = set_context_scheduling_priority(process, args.context,
+ args.priority, false);
+cleanup:
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+get_context_scheduling_priority(struct dxgprocess *process,
+ struct d3dkmthandle hcontext,
+ int __user *priority,
+ bool in_process)
+{
+ int ret;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ int pri = 0;
+
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGCONTEXT,
+ hcontext);
+ 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_get_context_sch_priority(process, adapter,
+ hcontext, &pri, in_process);
+ if (ret < 0)
+ goto cleanup;
+ ret = copy_to_user(priority, &pri, sizeof(pri));
+ if (ret) {
+ pr_err("%s failed to copy priority to user", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ return ret;
+}
+
+static int
+dxgk_get_context_scheduling_priority(struct dxgprocess *process,
+ void *__user inargs)
+{
+ struct d3dkmt_getcontextschedulingpriority args;
+ struct d3dkmt_getcontextschedulingpriority __user *input = inargs;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = get_context_scheduling_priority(process, args.context,
+ &input->priority, false);
+cleanup:
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_set_context_process_scheduling_priority(struct dxgprocess *process,
+ void *__user inargs)
+{
+ struct d3dkmt_setcontextinprocessschedulingpriority args;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = set_context_scheduling_priority(process, args.context,
+ args.priority, true);
+cleanup:
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_get_context_process_scheduling_priority(struct dxgprocess *process,
+ void __user *inargs)
+{
+ struct d3dkmt_getcontextinprocessschedulingpriority args;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = get_context_scheduling_priority(process, args.context,
+ &((struct d3dkmt_getcontextinprocessschedulingpriority *)
+ inargs)->priority, true);
+cleanup:
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_change_vidmem_reservation(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_changevideomemoryreservation args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ bool adapter_locked = false;
+
+ dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.process != 0) {
+ pr_err("setting memory reservation for other process");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+ adapter_locked = true;
+ args.adapter.v = 0;
+ ret = dxgvmb_send_change_vidmem_reservation(process, adapter,
+ zerohandle, &args);
+
+cleanup:
+
+ if (adapter_locked)
+ dxgadapter_release_lock_shared(adapter);
+ if (adapter)
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_query_clock_calibration(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_queryclockcalibration args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ bool adapter_locked = false;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+ adapter_locked = true;
+
+ args.adapter = adapter->host_handle;
+ ret = dxgvmb_send_query_clock_calibration(process, adapter,
+ &args, inargs);
+ if (ret < 0)
+ goto cleanup;
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy output args", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (adapter_locked)
+ dxgadapter_release_lock_shared(adapter);
+ if (adapter)
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ return ret;
+}
+
+static int
+dxgk_flush_heap_transitions(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_flushheaptransitions args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ bool adapter_locked = false;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+ adapter_locked = true;
+
+ args.adapter = adapter->host_handle;
+ ret = dxgvmb_send_flush_heap_transitions(process, adapter, &args);
+ if (ret < 0)
+ goto cleanup;
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy output args", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (adapter_locked)
+ dxgadapter_release_lock_shared(adapter);
+ if (adapter)
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ return ret;
+}
+
+static int
+dxgk_escape(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_escape args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ bool adapter_locked = false;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+ adapter_locked = true;
+
+ args.adapter = adapter->host_handle;
+ ret = dxgvmb_send_escape(process, adapter, &args);
+
+cleanup:
+
+ if (adapter_locked)
+ dxgadapter_release_lock_shared(adapter);
+ if (adapter)
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_query_vidmem_info(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_queryvideomemoryinfo args;
+ int ret;
+ struct dxgadapter *adapter = NULL;
+ bool adapter_locked = false;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.process != 0) {
+ pr_err("query vidmem info from another process ");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ adapter = NULL;
+ goto cleanup;
+ }
+ adapter_locked = true;
+
+ args.adapter = adapter->host_handle;
+ ret = dxgvmb_send_query_vidmem_info(process, adapter, &args, inargs);
+
+cleanup:
+
+ if (adapter_locked)
+ dxgadapter_release_lock_shared(adapter);
+ if (adapter)
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ if (ret < 0)
+ pr_err("%s failed: %x", __func__, ret);
+ return ret;
+}
+
+static int
+dxgk_get_device_state(struct dxgprocess *process, void *__user inargs)
+{
+ int ret;
+ struct d3dkmt_getdevicestate args;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ int global_device_state_counter = 0;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ 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;
+ }
+
+ if (args.state_type == _D3DKMT_DEVICESTATE_EXECUTION) {
+ global_device_state_counter =
+ atomic_read(&dxgglobal->device_state_counter);
+ if (device->execution_state_counter ==
+ global_device_state_counter) {
+ args.execution_state = device->execution_state;
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy args to user",
+ __func__);
+ ret = -EINVAL;
+ }
+ goto cleanup;
+ }
+ }
+
+ ret = dxgvmb_send_get_device_state(process, adapter, &args, inargs);
+
+ if (ret == 0 && args.state_type == _D3DKMT_DEVICESTATE_EXECUTION) {
+ device->execution_state = args.execution_state;
+ device->execution_state_counter = global_device_state_counter;
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+ if (ret < 0)
+ pr_err("%s failed %x", __func__, ret);
+
+ return ret;
+}
+
+static int
+dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj,
+ struct dxgprocess *process,
+ struct d3dkmthandle objecthandle)
+{
+ int ret = 0;
+
+ mutex_lock(&syncobj->fd_mutex);
+ if (syncobj->host_shared_handle_nt_reference == 0) {
+ ret = dxgvmb_send_create_nt_shared_object(process,
+ objecthandle,
+ &syncobj->host_shared_handle_nt);
+ if (ret < 0)
+ goto cleanup;
+ dev_dbg(dxgglobaldev, "Host_shared_handle_ht: %x",
+ syncobj->host_shared_handle_nt.v);
+ kref_get(&syncobj->ssyncobj_kref);
+ }
+ syncobj->host_shared_handle_nt_reference++;
+cleanup:
+ mutex_unlock(&syncobj->fd_mutex);
+ return ret;
+}
+
+static int
+dxgsharedresource_get_host_nt_handle(struct dxgsharedresource *resource,
+ struct dxgprocess *process,
+ struct d3dkmthandle objecthandle)
+{
+ int ret = 0;
+
+ mutex_lock(&resource->fd_mutex);
+ if (resource->host_shared_handle_nt_reference == 0) {
+ ret = dxgvmb_send_create_nt_shared_object(process,
+ objecthandle,
+ &resource->host_shared_handle_nt);
if (ret < 0)
goto cleanup;
dev_dbg(dxgglobaldev, "Resource host_shared_handle_ht: %x",
@@ -3431,8 +4778,10 @@ dxgk_share_objects(struct dxgprocess *process, void *__user inargs)
tmp = (u64) object_fd;
ret = copy_to_user(args.shared_handle, &tmp, sizeof(u64));
- if (ret < 0)
+ if (ret) {
pr_err("%s failed to copy shared handle", __func__);
+ ret = -EINVAL;
+ }
cleanup:
if (ret < 0) {
@@ -3453,6 +4802,13 @@ dxgk_share_objects(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgk_invalidate_cache(struct dxgprocess *process, void *__user inargs)
+{
+ pr_err("%s is not implemented", __func__);
+ return -ENOTTY;
+}
+
static int
dxgk_query_resource_info(struct dxgprocess *process, void *__user inargs)
{
@@ -3469,8 +4825,6 @@ dxgk_query_resource_info_nt(struct dxgprocess *process, void *__user inargs)
struct dxgsharedresource *shared_resource = NULL;
struct file *file = NULL;
- dev_dbg(dxgglobaldev, "ioctl: %s", __func__);
-
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
pr_err("%s failed to copy input args", __func__);
@@ -3525,8 +4879,10 @@ dxgk_query_resource_info_nt(struct dxgprocess *process, void *__user inargs)
shared_resource->alloc_private_data_size;
ret = copy_to_user(inargs, &args, sizeof(args));
- if (ret < 0)
+ if (ret) {
pr_err("%s failed to copy output args", __func__);
+ ret = -EINVAL;
+ }
cleanup:
@@ -3587,8 +4943,9 @@ assign_resource_handles(struct dxgprocess *process,
ret = copy_to_user(&args->open_alloc_info[i],
&open_alloc_info,
sizeof(open_alloc_info));
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy alloc info", __func__);
+ ret = -EINVAL;
goto cleanup;
}
}
@@ -3738,8 +5095,9 @@ open_resource(struct dxgprocess *process,
ret = copy_to_user(args->private_runtime_data,
shared_resource->runtime_private_data,
shared_resource->runtime_private_data_size);
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy runtime data", __func__);
+ ret = -EINVAL;
goto cleanup;
}
}
@@ -3748,8 +5106,9 @@ open_resource(struct dxgprocess *process,
ret = copy_to_user(args->resource_priv_drv_data,
shared_resource->resource_private_data,
shared_resource->resource_private_data_size);
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy resource data", __func__);
+ ret = -EINVAL;
goto cleanup;
}
}
@@ -3758,8 +5117,9 @@ open_resource(struct dxgprocess *process,
ret = copy_to_user(args->total_priv_drv_data,
shared_resource->alloc_private_data,
shared_resource->alloc_private_data_size);
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy alloc data", __func__);
+ ret = -EINVAL;
goto cleanup;
}
}
@@ -3772,15 +5132,18 @@ open_resource(struct dxgprocess *process,
ret = copy_to_user(res_out, &resource_handle,
sizeof(struct d3dkmthandle));
- if (ret < 0) {
+ if (ret) {
pr_err("%s failed to copy resource handle to user", __func__);
+ ret = -EINVAL;
goto cleanup;
}
ret = copy_to_user(total_driver_data_size_out,
&args->total_priv_drv_data_size, sizeof(u32));
- if (ret < 0)
+ if (ret) {
pr_err("%s failed to copy total driver data size", __func__);
+ ret = -EINVAL;
+ }
cleanup:
@@ -3849,6 +5212,37 @@ dxgk_open_resource_nt(struct dxgprocess *process,
return ret;
}
+static int
+dxgk_share_object_with_host(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_shareobjectwithhost args;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_share_object_with_host(process, &args);
+ if (ret) {
+ pr_err("dxgvmb_send_share_object_with_host dailed");
+ goto cleanup;
+ }
+
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy data to user", __func__);
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
static int
dxgk_render(struct dxgprocess *process, void *__user inargs)
{
@@ -3941,8 +5335,20 @@ void init_ioctls(void)
LX_DXCREATEALLOCATION);
SET_IOCTL(/*0x7 */ dxgk_create_paging_queue,
LX_DXCREATEPAGINGQUEUE);
+ SET_IOCTL(/*0x8 */ dxgk_reserve_gpu_va,
+ LX_DXRESERVEGPUVIRTUALADDRESS);
SET_IOCTL(/*0x9 */ dxgk_query_adapter_info,
LX_DXQUERYADAPTERINFO);
+ SET_IOCTL(/*0xa */ dxgk_query_vidmem_info,
+ LX_DXQUERYVIDEOMEMORYINFO);
+ SET_IOCTL(/*0xb */ dxgk_make_resident,
+ LX_DXMAKERESIDENT);
+ SET_IOCTL(/*0xc */ dxgk_map_gpu_va,
+ LX_DXMAPGPUVIRTUALADDRESS);
+ SET_IOCTL(/*0xd */ dxgk_escape,
+ LX_DXESCAPE);
+ SET_IOCTL(/*0xe */ dxgk_get_device_state,
+ LX_DXGETDEVICESTATE);
SET_IOCTL(/*0xf */ dxgk_submit_command,
LX_DXSUBMITCOMMAND);
SET_IOCTL(/*0x10 */ dxgk_create_sync_object,
@@ -3957,6 +5363,8 @@ void init_ioctls(void)
LX_DXENUMADAPTERS2);
SET_IOCTL(/*0x15 */ dxgk_close_adapter,
LX_DXCLOSEADAPTER);
+ SET_IOCTL(/*0x16 */ dxgk_change_vidmem_reservation,
+ LX_DXCHANGEVIDEOMEMORYRESERVATION);
SET_IOCTL(/*0x17 */ dxgk_create_hwcontext,
LX_DXCREATEHWCONTEXT);
SET_IOCTL(/*0x18 */ dxgk_create_hwqueue,
@@ -3971,16 +5379,44 @@ void init_ioctls(void)
LX_DXDESTROYPAGINGQUEUE);
SET_IOCTL(/*0x1d */ dxgk_destroy_sync_object,
LX_DXDESTROYSYNCHRONIZATIONOBJECT);
+ SET_IOCTL(/*0x1e */ dxgk_evict,
+ LX_DXEVICT);
+ SET_IOCTL(/*0x1f */ dxgk_flush_heap_transitions,
+ LX_DXFLUSHHEAPTRANSITIONS);
+ SET_IOCTL(/*0x20 */ dxgk_free_gpu_va,
+ LX_DXFREEGPUVIRTUALADDRESS);
+ SET_IOCTL(/*0x21 */ dxgk_get_context_process_scheduling_priority,
+ LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY);
+ SET_IOCTL(/*0x22 */ dxgk_get_context_scheduling_priority,
+ LX_DXGETCONTEXTSCHEDULINGPRIORITY);
SET_IOCTL(/*0x23 */ dxgk_get_shared_resource_adapter_luid,
LX_DXGETSHAREDRESOURCEADAPTERLUID);
+ SET_IOCTL(/*0x24 */ dxgk_invalidate_cache,
+ LX_DXINVALIDATECACHE);
+ SET_IOCTL(/*0x25 */ dxgk_lock2,
+ LX_DXLOCK2);
+ SET_IOCTL(/*0x26 */ dxgk_mark_device_as_error,
+ LX_DXMARKDEVICEASERROR);
+ SET_IOCTL(/*0x27 */ dxgk_offer_allocations,
+ LX_DXOFFERALLOCATIONS);
SET_IOCTL(/*0x28 */ dxgk_open_resource,
LX_DXOPENRESOURCE);
SET_IOCTL(/*0x29 */ dxgk_open_sync_object,
LX_DXOPENSYNCHRONIZATIONOBJECT);
+ SET_IOCTL(/*0x2a */ dxgk_query_alloc_residency,
+ LX_DXQUERYALLOCATIONRESIDENCY);
SET_IOCTL(/*0x2b */ dxgk_query_resource_info,
LX_DXQUERYRESOURCEINFO);
+ SET_IOCTL(/*0x2c */ dxgk_reclaim_allocations,
+ LX_DXRECLAIMALLOCATIONS2);
SET_IOCTL(/*0x2d */ dxgk_render,
LX_DXRENDER);
+ SET_IOCTL(/*0x2e */ dxgk_set_allocation_priority,
+ LX_DXSETALLOCATIONPRIORITY);
+ SET_IOCTL(/*0x2f */ dxgk_set_context_process_scheduling_priority,
+ LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY);
+ SET_IOCTL(/*0x30 */ dxgk_set_context_scheduling_priority,
+ LX_DXSETCONTEXTSCHEDULINGPRIORITY);
SET_IOCTL(/*0x31 */ dxgk_signal_sync_object_cpu,
LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU);
SET_IOCTL(/*0x32 */ dxgk_signal_sync_object_gpu,
@@ -3993,10 +5429,20 @@ void init_ioctls(void)
LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE);
SET_IOCTL(/*0x36 */ dxgk_submit_signal_to_hwqueue,
LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE);
+ SET_IOCTL(/*0x37 */ dxgk_unlock2,
+ LX_DXUNLOCK2);
+ SET_IOCTL(/*0x38 */ dxgk_update_alloc_property,
+ LX_DXUPDATEALLOCPROPERTY);
+ SET_IOCTL(/*0x39 */ dxgk_update_gpu_va,
+ LX_DXUPDATEGPUVIRTUALADDRESS);
SET_IOCTL(/*0x3a */ dxgk_wait_sync_object_cpu,
LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU);
SET_IOCTL(/*0x3b */ dxgk_wait_sync_object_gpu,
LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU);
+ SET_IOCTL(/*0x3c */ dxgk_get_allocation_priority,
+ LX_DXGETALLOCATIONPRIORITY);
+ SET_IOCTL(/*0x3d */ dxgk_query_clock_calibration,
+ LX_DXQUERYCLOCKCALIBRATION);
SET_IOCTL(/*0x3e */ dxgk_enum_adapters3,
LX_DXENUMADAPTERS3);
SET_IOCTL(/*0x3f */ dxgk_share_objects,
@@ -4007,4 +5453,8 @@ void init_ioctls(void)
LX_DXQUERYRESOURCEINFOFROMNTHANDLE);
SET_IOCTL(/*0x42 */ dxgk_open_resource_nt,
LX_DXOPENRESOURCEFROMNTHANDLE);
+ SET_IOCTL(/*0x43 */ dxgk_query_statistics,
+ LX_DXQUERYSTATISTICS);
+ SET_IOCTL(/*0x44 */ dxgk_share_object_with_host,
+ LX_DXSHAREOBJECTWITHHOST);
}
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls
2022-01-12 19:55 ` [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls Iouri Tarassov
@ 2022-01-13 7:47 ` Greg KH
2022-01-14 0:19 ` Iouri Tarassov
0 siblings, 1 reply; 33+ messages in thread
From: Greg KH @ 2022-01-13 7:47 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On Wed, Jan 12, 2022 at 11:55:13AM -0800, Iouri Tarassov wrote:
> Implement various WDDM IOCTLs.
>
> - IOCTLs to handle GPU virtual addressing (VA):
> LX_DXRESERVEGPUVIRTUALADDRESS (D3DKMTReserveGpuVertualAddress)
> LX_DXFREEGPUVIRTUALADDRESS (D3DKMTFreeGpuVertualAddress)
> LX_DXMAPGPUVIRTUALADDRESS (D3DKMTMapGpuVertualAddress)
> LX_DXUPDATEGPUVIRTUALADDRESS (D3DKMTUpdateGpuVertualAddress)
>
> WDDM supports a compute device to use GPU virtual addresses when
> accessing allocation memory. A GPU VA could be reserved or mapped
> to a GPU allocation. The video memory manager on the host updates
> GPU page tables for the virtual addresses.
>
> - IOCTLs to manage residency of GPU accessing allocations:
> LX_DXMAKERESIDENT (D3DKMTMakeResident)
> LX_DXEVICT (D3DKMTEvict)
>
> An allocation is resident when GPU is setup to access it. The
> current WDDM design does not support on demand GPU page faulting.
> An allocation must be resident (be in the local device memory or
> in non-pageable system memory) before GPU is allowed to access it.
>
> - IOCTLs to offer/reclaim alloctions:
> LX_DXOFFERALLOCATIONS {D3DKMTOfferAllocations)
> LX_DXRECLAIMALLOCATIONS2 (D3DKMTReclaimAllocations)
>
> When a user mode driver does not need an allocation, it can
> "offer" it. This means that the allocation is not in use and it
> local device memory could be reclaimed and given to another allocation.
> When the allocation is again needed, the caller can "reclaim" the
> allocations. If the allocation is still in the device local memory,
> the reclaim operation succeeds. If not the called must restore the
> content of the allocation before it can be used by the device.
>
> - LX_DXESCAPE (D3DKMTEscape)
> This IOCTL is used to send/receive private data between user mode
> driver and kernel mode driver. This is an extension of the WDDM APIs.
>
> - LX_DXGETDEVICESTATE (D3DKMTGetDeviceState)
> The IOCTL is used to get the current execution state of the dxgdevice
> object.
>
> - LX_DXMARKDEVICEASERROR (D3DKMTMarkDeviceAsError)
> The IOCTL is used to bring the dxgdevice object to the error state.
> Subsequent calls to use the device object will fail.
>
> - LX_DXQUERYSTATISTICS (D3DKMTQuerystatistics)
> The IOCTL is used to query various statistics from the compute device
> on the host.
>
> - IOCTLs to deal with execution context priorities
> LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY
> LX_DXGETCONTEXTSCHEDULINGPRIORITY
> LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY
> LX_DXSETCONTEXTSCHEDULINGPRIORITY
>
> Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
> ---
> drivers/hv/dxgkrnl/dxgkrnl.h | 2 +
> drivers/hv/dxgkrnl/dxgvmbus.c | 1466 ++++++++++++++++++++++++++++---
> drivers/hv/dxgkrnl/dxgvmbus.h | 15 +
> drivers/hv/dxgkrnl/ioctl.c | 1524 ++++++++++++++++++++++++++++++++-
> 4 files changed, 2831 insertions(+), 176 deletions(-)
Again, break this up into smaller pieces. Would you want to review all
of these at the same time?
Remember, you write code for people to review and understand first, and
the compiler second. With large changes like this, you are making it
difficult for people to review, which is your target audience.
I'll stop here, please fix up this patch series into something that is
reviewable.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls
2022-01-13 7:47 ` Greg KH
@ 2022-01-14 0:19 ` Iouri Tarassov
2022-01-14 5:38 ` Greg KH
0 siblings, 1 reply; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-14 0:19 UTC (permalink / raw)
To: Greg KH
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On 1/12/2022 11:47 PM, Greg KH wrote:
> On Wed, Jan 12, 2022 at 11:55:13AM -0800, Iouri Tarassov wrote:
> > Implement various WDDM IOCTLs.
> >
> Again, break this up into smaller pieces. Would you want to review all
> of these at the same time?
>
> Remember, you write code for people to review and understand first, and
> the compiler second. With large changes like this, you are making it
> difficult for people to review, which is your target audience.
>
> I'll stop here, please fix up this patch series into something that is
> reviewable.
Hi Greg,
https://www.kernel.org/doc/html/latest/process/submitting-patches.html
states that "only post say 15 [patches] or so at a time and wait for
review and integration".
The IOCTLs here are simple and I tried to keep the number of patches smaller
than 15. Is it ok to have more than 15 patches in a submission, or I
need to
submit the driver is several chunks (some of which would be not fully
functional)?
Thanks
Iouri
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls
2022-01-14 0:19 ` Iouri Tarassov
@ 2022-01-14 5:38 ` Greg KH
2022-01-15 2:16 ` Iouri Tarassov
0 siblings, 1 reply; 33+ messages in thread
From: Greg KH @ 2022-01-14 5:38 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On Thu, Jan 13, 2022 at 04:19:41PM -0800, Iouri Tarassov wrote:
>
> On 1/12/2022 11:47 PM, Greg KH wrote:
> > On Wed, Jan 12, 2022 at 11:55:13AM -0800, Iouri Tarassov wrote:
> > > Implement various WDDM IOCTLs.
> > > Again, break this up into smaller pieces. Would you want to review
> > all
> > of these at the same time?
> >
> > Remember, you write code for people to review and understand first, and
> > the compiler second. With large changes like this, you are making it
> > difficult for people to review, which is your target audience.
> >
> > I'll stop here, please fix up this patch series into something that is
> > reviewable.
>
> Hi Greg,
>
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html
> states that "only post say 15 [patches] or so at a time and wait for review
> and integration".
> The IOCTLs here are simple and I tried to keep the number of patches smaller
> than 15. Is it ok to have more than 15 patches in a submission, or I need to
> submit the driver is several chunks (some of which would be not fully
> functional)?
We get patch series that are much longer all the time, that's fine. How
many do you feel would be needed to properly break this out?
Again, create changes to make review easy.
greg k-h
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls
2022-01-14 5:38 ` Greg KH
@ 2022-01-15 2:16 ` Iouri Tarassov
0 siblings, 0 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-15 2:16 UTC (permalink / raw)
To: Greg KH
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On 1/13/2022 9:38 PM, Greg KH wrote:
> On Thu, Jan 13, 2022 at 04:19:41PM -0800, Iouri Tarassov wrote:
> >
> > On 1/12/2022 11:47 PM, Greg KH wrote:
> > > On Wed, Jan 12, 2022 at 11:55:13AM -0800, Iouri Tarassov wrote:
> > > > Implement various WDDM IOCTLs.
> > > > Again, break this up into smaller pieces. Would you want to review
> > > all
> > > of these at the same time?
> > >
> > > Remember, you write code for people to review and understand first, and
> > > the compiler second. With large changes like this, you are making it
> > > difficult for people to review, which is your target audience.
> > >
> > > I'll stop here, please fix up this patch series into something that is
> > > reviewable.
> >
> > Hi Greg,
> >
> > https://www.kernel.org/doc/html/latest/process/submitting-patches.html
> > states that "only post say 15 [patches] or so at a time and wait for review
> > and integration".
> > The IOCTLs here are simple and I tried to keep the number of patches smaller
> > than 15. Is it ok to have more than 15 patches in a submission, or I need to
> > submit the driver is several chunks (some of which would be not fully
> > functional)?
>
> We get patch series that are much longer all the time, that's fine. How
> many do you feel would be needed to properly break this out?
Hi Greg,
I think there could be 20-25 patches.
Implementation of many IOCTLs follow the same pattern:
- add the IOCTL definition to the ioctl table
- implement a function to send the corresponding VM bus message to the host
- implement a function to handle the IOCTL input data, call the function to send
message to the host and copy results back to the caller.
I tried to combine several such implementations to a single patch.
I think the patch is logically simple and it would be easy to review.
What is your opinion?
Thanks
Iouri
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
` (6 preceding siblings ...)
2022-01-12 19:55 ` [PATCH v1 8/9] drivers: hv: dxgkrnl: Implement various WDDM ioctls Iouri Tarassov
@ 2022-01-12 19:55 ` Iouri Tarassov
2022-01-13 7:41 ` Greg KH
2022-01-14 18:03 ` Daniel Vetter
2022-01-12 22:12 ` [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Nathan Chancellor
[not found] ` <1b26482b50832b95a9d8532c493cee6c97323b87.1641937419.git.iourit@linux.microsoft.com>
9 siblings, 2 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 19:55 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: linux-kernel, spronovo, gregkh
Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile).
dxgsyncfile is built on top of the Linux sync_file object and
provides a way for the user mode to synchronize with the execution
of the device DMA packets.
The IOCTL creates a dxgsyncfile object for the given GPU synchronization
object and a fence value. A sync_object file descriptor is returned to
the caller. The caller could wait for the object by using poll().
When the GPU synchronization object is signaled on the host, the host
sends a message to the virtual machine and the sync_file object is
signaled.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/Kconfig | 2 +
drivers/hv/dxgkrnl/Makefile | 2 +-
drivers/hv/dxgkrnl/dxgkrnl.h | 2 +
drivers/hv/dxgkrnl/dxgmodule.c | 44 ++++++-
drivers/hv/dxgkrnl/dxgsyncfile.c | 210 +++++++++++++++++++++++++++++++
drivers/hv/dxgkrnl/dxgsyncfile.h | 30 +++++
drivers/hv/dxgkrnl/dxgvmbus.c | 145 ++++++++++++++-------
drivers/hv/dxgkrnl/dxgvmbus.h | 12 ++
drivers/hv/dxgkrnl/ioctl.c | 10 +-
drivers/hv/dxgkrnl/misc.c | 6 +
drivers/hv/dxgkrnl/misc.h | 1 +
11 files changed, 414 insertions(+), 50 deletions(-)
create mode 100644 drivers/hv/dxgkrnl/dxgsyncfile.c
create mode 100644 drivers/hv/dxgkrnl/dxgsyncfile.h
diff --git a/drivers/hv/dxgkrnl/Kconfig b/drivers/hv/dxgkrnl/Kconfig
index 22d0914d8f1e..63b3eff9af5b 100644
--- a/drivers/hv/dxgkrnl/Kconfig
+++ b/drivers/hv/dxgkrnl/Kconfig
@@ -6,6 +6,8 @@ config DXGKRNL
tristate "Microsoft Paravirtualized GPU support"
depends on HYPERV
depends on 64BIT || COMPILE_TEST
+ select DMA_SHARED_BUFFER
+ select SYNC_FILE
help
This driver supports paravirtualized virtual compute devices, exposed
by Microsoft Hyper-V when Linux is running inside of a virtual machine
diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile
index 745c66bebe5d..5fe06c27a1f2 100644
--- a/drivers/hv/dxgkrnl/Makefile
+++ b/drivers/hv/dxgkrnl/Makefile
@@ -2,4 +2,4 @@
# Makefile for the Linux video drivers.
obj-$(CONFIG_DXGKRNL) += dxgkrnl.o
-dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
+dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o dxgsyncfile.o
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 73d917cb11d5..b6ae31bcdb50 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -307,6 +307,7 @@ struct dxgglobal {
bool pci_registered;
bool global_channel_initialized;
bool async_msg_enabled;
+ bool map_guest_pages_enabled;
};
extern struct dxgglobal *dxgglobal;
@@ -830,6 +831,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
struct
d3dkmt_waitforsynchronizationobjectfromcpu
*args,
+ bool user_address,
u64 cpu_event);
int dxgvmb_send_lock2(struct dxgprocess *process,
struct dxgadapter *adapter,
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index d50c1140c68f..1e3d8b5c1112 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -15,8 +15,10 @@
#include <linux/eventfd.h>
#include <linux/hyperv.h>
#include <linux/pci.h>
+#include <linux/sync_file.h>
#include "dxgkrnl.h"
+#include "dxgsyncfile.h"
struct dxgglobal *dxgglobal;
struct device *dxgglobaldev;
@@ -134,7 +136,7 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
void signal_host_cpu_event(struct dxghostevent *eventhdr)
{
- struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
+ struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
if (event->remove_from_list ||
event->destroy_after_signal) {
@@ -157,6 +159,15 @@ void signal_host_cpu_event(struct dxghostevent *eventhdr)
}
}
+void signal_dma_fence(struct dxghostevent *eventhdr)
+{
+ struct dxgsyncpoint *event = (struct dxgsyncpoint *)eventhdr;
+
+ event->fence_value++;
+ list_del(&eventhdr->host_event_list_entry);
+ dma_fence_signal(&event->base);
+}
+
void dxgglobal_signal_host_event(u64 event_id)
{
struct dxghostevent *event;
@@ -172,6 +183,8 @@ void dxgglobal_signal_host_event(u64 event_id)
event_id);
if (event->event_type == dxghostevent_cpu_event)
signal_host_cpu_event(event);
+ else if (event->event_type == dxghostevent_dma_fence)
+ signal_dma_fence(event);
else
pr_err("Unknown host event type");
break;
@@ -404,6 +417,9 @@ const struct file_operations dxgk_fops = {
/* Luid of the virtual GPU on the host (struct winluid) */
#define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
sizeof(u32))
+/* The host caps (dxgk_vmbus_hostcaps) */
+#define DXGK_VMBUS_HOSTCAPS_OFFSET (DXGK_VMBUS_VGPU_LUID_OFFSET + \
+ sizeof(struct winluid))
/* The guest writes its capavilities to this adderss */
#define DXGK_VMBUS_GUESTCAPS_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
sizeof(u32))
@@ -418,6 +434,24 @@ struct dxgk_vmbus_guestcaps {
};
};
+/*
+ * The structure defines features, supported by the host.
+ *
+ * map_guest_memory
+ * Host can map guest memory pages, so the guest can avoid using GPADLs
+ * to represent existing system memory allocations.
+ */
+struct dxgk_vmbus_hostcaps {
+ union {
+ struct {
+ u32 map_guest_memory : 1;
+ u32 reserved : 31;
+ };
+ u32 host_caps;
+ };
+};
+
+
static int dxg_pci_read_dwords(struct pci_dev *dev, int offset, int size,
void *val)
{
@@ -444,6 +478,7 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
u32 vmbus_interface_ver = DXGK_VMBUS_INTERFACE_VERSION;
struct winluid vgpu_luid = {};
struct dxgk_vmbus_guestcaps guest_caps = {.wsl2 = 1};
+ struct dxgk_vmbus_hostcaps host_caps = {};
mutex_lock(&dxgglobal->device_mutex);
@@ -472,6 +507,13 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
if (ret)
goto cleanup;
+ ret = pci_read_config_dword(dev, DXGK_VMBUS_HOSTCAPS_OFFSET,
+ &host_caps.host_caps);
+ if (ret == 0) {
+ if (host_caps.map_guest_memory)
+ dxgglobal->map_guest_pages_enabled = true;
+ }
+
if (dxgglobal->vmbus_ver > DXGK_VMBUS_INTERFACE_VERSION)
dxgglobal->vmbus_ver = DXGK_VMBUS_INTERFACE_VERSION;
}
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.c b/drivers/hv/dxgkrnl/dxgsyncfile.c
new file mode 100644
index 000000000000..f0705be548e0
--- /dev/null
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2019, Microsoft Corporation.
+ *
+ * Author:
+ * Iouri Tarassov <iourit@linux.microsoft.com>
+ *
+ * Dxgkrnl Graphics Driver
+ * Ioctl implementation
+ *
+ */
+
+#include <linux/eventfd.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/anon_inodes.h>
+#include <linux/mman.h>
+
+#include "dxgkrnl.h"
+#include "dxgvmbus.h"
+#include "dxgsyncfile.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "dxgk:err: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
+
+static const struct dma_fence_ops dxgdmafence_ops;
+
+static inline struct dxgsyncpoint *to_syncpoint(struct dma_fence *fence)
+{
+ if (fence->ops != &dxgdmafence_ops)
+ return NULL;
+ return container_of(fence, struct dxgsyncpoint, base);
+}
+
+int dxgk_create_sync_file(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_createsyncfile args;
+ struct dxgsyncpoint *pt;
+ int ret = 0;
+ int fd = get_unused_fd_flags(O_CLOEXEC);
+ struct sync_file *sync_file = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct d3dkmt_waitforsynchronizationobjectfromcpu waitargs = {};
+
+ if (fd < 0) {
+ pr_err("get_unused_fd_flags failed: %d", fd);
+ ret = fd;
+ goto cleanup;
+ }
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy input args", __func__);
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ pr_err("dxgprocess_device_by_handle failed");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ pr_err("dxgdevice_acquire_lock_shared failed");
+ device = NULL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ pr_err("dxgadapter_acquire_lock_shared failed");
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ pt = kzalloc(sizeof(*pt), GFP_KERNEL);
+ if (!pt) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ spin_lock_init(&pt->lock);
+ pt->fence_value = args.fence_value;
+ pt->context = dma_fence_context_alloc(1);
+ pt->hdr.event_id = dxgglobal_new_host_event_id();
+ pt->hdr.event_type = dxghostevent_dma_fence;
+ dxgglobal_add_host_event(&pt->hdr);
+
+ dma_fence_init(&pt->base, &dxgdmafence_ops, &pt->lock,
+ pt->context, args.fence_value);
+
+ sync_file = sync_file_create(&pt->base);
+ if (sync_file == NULL) {
+ pr_err("sync_file_create failed");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ dma_fence_put(&pt->base);
+
+ waitargs.device = args.device;
+ waitargs.object_count = 1;
+ waitargs.objects = &args.monitored_fence;
+ waitargs.fence_values = &args.fence_value;
+ ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
+ &waitargs, false,
+ pt->hdr.event_id);
+ if (ret < 0) {
+ pr_err("dxgvmb_send_wait_sync_object_cpu failed");
+ goto cleanup;
+ }
+
+ args.sync_file_handle = (u64)fd;
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ pr_err("%s failed to copy output args", __func__);
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ fd_install(fd, sync_file->file);
+
+cleanup:
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ dxgdevice_release_lock_shared(device);
+ if (ret) {
+ if (sync_file) {
+ fput(sync_file->file);
+ /* sync_file_release will destroy dma_fence */
+ pt = NULL;
+ }
+ if (pt)
+ dma_fence_put(&pt->base);
+ if (fd >= 0)
+ put_unused_fd(fd);
+ }
+ dev_dbg(dxgglobaldev, "ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ return ret;
+}
+
+static const char *dxgdmafence_get_driver_name(struct dma_fence *fence)
+{
+ return "dxgkrnl";
+}
+
+static const char *dxgdmafence_get_timeline_name(struct dma_fence *fence)
+{
+ return "no_timeline";
+}
+
+static void dxgdmafence_release(struct dma_fence *fence)
+{
+ struct dxgsyncpoint *syncpoint;
+
+ syncpoint = to_syncpoint(fence);
+ if (syncpoint) {
+ if (syncpoint->hdr.event_id)
+ dxgglobal_get_host_event(syncpoint->hdr.event_id);
+ kfree(syncpoint);
+ }
+}
+
+static bool dxgdmafence_signaled(struct dma_fence *fence)
+{
+ struct dxgsyncpoint *syncpoint;
+
+ syncpoint = to_syncpoint(fence);
+ if (syncpoint == 0)
+ return true;
+ return __dma_fence_is_later(syncpoint->fence_value, fence->seqno,
+ fence->ops);
+}
+
+static bool dxgdmafence_enable_signaling(struct dma_fence *fence)
+{
+ return true;
+}
+
+static void dxgdmafence_value_str(struct dma_fence *fence,
+ char *str, int size)
+{
+ snprintf(str, size, "%lld", fence->seqno);
+}
+
+static void dxgdmafence_timeline_value_str(struct dma_fence *fence,
+ char *str, int size)
+{
+ struct dxgsyncpoint *syncpoint;
+
+ syncpoint = to_syncpoint(fence);
+ snprintf(str, size, "%lld", syncpoint->fence_value);
+}
+
+static const struct dma_fence_ops dxgdmafence_ops = {
+ .get_driver_name = dxgdmafence_get_driver_name,
+ .get_timeline_name = dxgdmafence_get_timeline_name,
+ .enable_signaling = dxgdmafence_enable_signaling,
+ .signaled = dxgdmafence_signaled,
+ .release = dxgdmafence_release,
+ .fence_value_str = dxgdmafence_value_str,
+ .timeline_value_str = dxgdmafence_timeline_value_str,
+};
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.h b/drivers/hv/dxgkrnl/dxgsyncfile.h
new file mode 100644
index 000000000000..a91fb2ecd372
--- /dev/null
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2019, Microsoft Corporation.
+ *
+ * Author:
+ * Iouri Tarassov <iourit@linux.microsoft.com>
+ *
+ * Dxgkrnl Graphics Driver
+ * Headers for sync file objects
+ *
+ */
+
+#ifndef _DXGSYNCFILE_H
+#define _DXGSYNCFILE_H
+
+#include <linux/sync_file.h>
+
+int dxgk_create_sync_file(struct dxgprocess *process, void *__user inargs);
+
+struct dxgsyncpoint {
+ struct dxghostevent hdr;
+ struct dma_fence base;
+ u64 fence_value;
+ u64 context;
+ spinlock_t lock;
+ u64 u64;
+};
+
+#endif /* _DXGSYNCFILE_H */
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 773d8f364b34..185fb7e38c21 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1311,15 +1311,18 @@ int create_existing_sysmem(struct dxgdevice *device,
void *kmem = NULL;
int ret = 0;
struct dxgkvmb_command_setexistingsysmemstore *set_store_command;
+ struct dxgkvmb_command_setexistingsysmempages *set_pages_command;
u64 alloc_size = host_alloc->allocation_size;
u32 npages = alloc_size >> PAGE_SHIFT;
struct dxgvmbusmsg msg = {.hdr = NULL};
-
- ret = init_message(&msg, device->adapter, device->process,
- sizeof(*set_store_command));
- if (ret)
- goto cleanup;
- set_store_command = (void *)msg.msg;
+ const u32 max_pfns_in_message =
+ (DXG_MAX_VM_BUS_PACKET_SIZE - sizeof(*set_pages_command) -
+ PAGE_SIZE) / sizeof(__u64);
+ u32 alloc_offset_in_pages = 0;
+ struct page **page_in;
+ u64 *pfn;
+ u32 pages_to_send;
+ u32 i;
/*
* Create a guest physical address list and set it as the allocation
@@ -1330,6 +1333,7 @@ int create_existing_sysmem(struct dxgdevice *device,
dev_dbg(dxgglobaldev, " Alloc size: %lld", alloc_size);
dxgalloc->cpu_address = (void *)sysmem;
+
dxgalloc->pages = vzalloc(npages * sizeof(void *));
if (dxgalloc->pages == NULL) {
pr_err("failed to allocate pages");
@@ -1347,31 +1351,80 @@ int create_existing_sysmem(struct dxgdevice *device,
ret = -ENOMEM;
goto cleanup;
}
- kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
- if (kmem == NULL) {
- pr_err("vmap failed");
- ret = -ENOMEM;
- goto cleanup;
- }
- ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
- alloc_size, &dxgalloc->gpadl);
- if (ret1) {
- pr_err("establish_gpadl failed: %d", ret1);
- ret = -ENOMEM;
- goto cleanup;
- }
- dev_dbg(dxgglobaldev, "New gpadl %d", dxgalloc->gpadl.gpadl_handle);
+ if (!dxgglobal->map_guest_pages_enabled) {
+ ret = init_message(&msg, device->adapter, device->process,
+ sizeof(*set_store_command));
+ if (ret)
+ goto cleanup;
+ set_store_command = (void *)msg.msg;
- command_vgpu_to_host_init2(&set_store_command->hdr,
- DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
- device->process->host_handle);
- set_store_command->device = device->handle;
- set_store_command->device = device->handle;
- set_store_command->allocation = host_alloc->allocation;
- set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
- ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
- if (ret < 0)
- pr_err("failed to set existing store: %x", ret);
+ kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
+ if (kmem == NULL) {
+ pr_err("vmap failed");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
+ alloc_size, &dxgalloc->gpadl);
+ if (ret1) {
+ pr_err("establish_gpadl failed: %d", ret1);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ dev_dbg(dxgglobaldev, "New gpadl %d",
+ dxgalloc->gpadl.gpadl_handle);
+
+ command_vgpu_to_host_init2(&set_store_command->hdr,
+ DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
+ device->process->host_handle);
+ set_store_command->device = device->handle;
+ set_store_command->allocation = host_alloc->allocation;
+ set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
+ msg.size);
+ if (ret < 0)
+ pr_err("failed to set existing store: %x", ret);
+ } else {
+ /*
+ * Send the list of the allocation PFNs to the host. The host
+ * will map the pages for GPU access.
+ */
+
+ ret = init_message(&msg, device->adapter, device->process,
+ sizeof(*set_pages_command) +
+ max_pfns_in_message * sizeof(u64));
+ if (ret)
+ goto cleanup;
+ set_pages_command = (void *)msg.msg;
+ command_vgpu_to_host_init2(&set_pages_command->hdr,
+ DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES,
+ device->process->host_handle);
+ set_pages_command->device = device->handle;
+ set_pages_command->allocation = host_alloc->allocation;
+
+ page_in = dxgalloc->pages;
+ while (alloc_offset_in_pages < npages) {
+ pfn = (u64 *)((char *)msg.msg +
+ sizeof(*set_pages_command));
+ pages_to_send = min(npages - alloc_offset_in_pages,
+ max_pfns_in_message);
+ set_pages_command->num_pages = pages_to_send;
+ set_pages_command->alloc_offset_in_pages =
+ alloc_offset_in_pages;
+
+ for (i = 0; i < pages_to_send; i++)
+ *pfn++ = page_to_pfn(*page_in++);
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel,
+ msg.hdr,
+ msg.size);
+ if (ret < 0) {
+ pr_err("failed to set existing pages: %x", ret);
+ break;
+ }
+ alloc_offset_in_pages += pages_to_send;
+ }
+ }
cleanup:
if (kmem)
@@ -2685,6 +2738,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
struct
d3dkmt_waitforsynchronizationobjectfromcpu
*args,
+ bool user_address,
u64 cpu_event)
{
int ret = -EINVAL;
@@ -2708,18 +2762,25 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
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) {
- pr_err("%s failed to copy objects", __func__);
- ret = -EINVAL;
- goto cleanup;
- }
- current_pos += object_size;
- ret = copy_from_user(current_pos, args->fence_values, fence_size);
- if (ret) {
- pr_err("%s failed to copy fences", __func__);
- ret = -EINVAL;
- goto cleanup;
+ if (user_address) {
+ ret = copy_from_user(current_pos, args->objects, object_size);
+ if (ret) {
+ pr_err("%s failed to copy objects", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ current_pos += object_size;
+ ret = copy_from_user(current_pos, args->fence_values,
+ fence_size);
+ if (ret) {
+ pr_err("%s failed to copy fences", __func__);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ } else {
+ memcpy(current_pos, args->objects, object_size);
+ current_pos += object_size;
+ memcpy(current_pos, args->fence_values, fence_size);
}
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index a19ac804a320..dc766d95a0c4 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -139,6 +139,8 @@ enum dxgkvmb_commandtype {
DXGK_VMBCOMMAND_GETCONTEXTSCHEDULINGPRIORITY = 61,
DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION = 62,
DXGK_VMBCOMMAND_QUERYRESOURCEINFO = 64,
+ DXGK_VMBCOMMAND_LOGEVENT = 65,
+ DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES = 66,
DXGK_VMBCOMMAND_INVALID
};
@@ -245,6 +247,16 @@ struct dxgkvmb_command_setexistingsysmemstore {
u32 gpadl;
};
+/* Returns ntstatus */
+struct dxgkvmb_command_setexistingsysmempages {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ struct d3dkmthandle device;
+ struct d3dkmthandle allocation;
+ u32 num_pages;
+ u32 alloc_offset_in_pages;
+ /* u64 pfn_array[num_pages] */
+};
+
struct dxgkvmb_command_createprocess {
struct dxgkvmb_command_vm_to_host hdr;
void *process;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 9770fabf163e..9236b6b95973 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -19,6 +19,7 @@
#include "dxgkrnl.h"
#include "dxgvmbus.h"
+#include "dxgsyncfile.h"
#undef pr_fmt
#define pr_fmt(fmt) "dxgk:err: " fmt
@@ -32,11 +33,6 @@ struct ioctl_desc {
};
static struct ioctl_desc ioctls[LX_IO_MAX + 1];
-static char *errorstr(int ret)
-{
- return ret < 0 ? "err" : "";
-}
-
static int dxgsyncobj_release(struct inode *inode, struct file *file)
{
struct dxgsharedsyncobject *syncobj = file->private_data;
@@ -3561,7 +3557,7 @@ dxgk_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
}
ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
- &args, event_id);
+ &args, true, event_id);
if (ret < 0)
goto cleanup;
@@ -5457,4 +5453,6 @@ void init_ioctls(void)
LX_DXQUERYSTATISTICS);
SET_IOCTL(/*0x44 */ dxgk_share_object_with_host,
LX_DXSHAREOBJECTWITHHOST);
+ SET_IOCTL(/*0x45 */ dxgk_create_sync_file,
+ LX_DXCREATESYNCFILE);
}
diff --git a/drivers/hv/dxgkrnl/misc.c b/drivers/hv/dxgkrnl/misc.c
index ffb491641836..1b152c269265 100644
--- a/drivers/hv/dxgkrnl/misc.c
+++ b/drivers/hv/dxgkrnl/misc.c
@@ -35,3 +35,9 @@ u16 *wcsncpy(u16 *dest, const u16 *src, size_t n)
dest[i - 1] = 0;
return dest;
}
+
+char *errorstr(int ret)
+{
+ return ret < 0 ? "err" : "";
+}
+
diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h
index 7fe3fc45b67c..3079dd55c7a4 100644
--- a/drivers/hv/dxgkrnl/misc.h
+++ b/drivers/hv/dxgkrnl/misc.h
@@ -44,6 +44,7 @@ extern const struct d3dkmthandle zerohandle;
*/
u16 *wcsncpy(u16 *dest, const u16 *src, size_t n);
+char *errorstr(int ret);
enum dxglockstate {
DXGLOCK_SHARED,
--
2.32.0
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-01-12 19:55 ` [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE Iouri Tarassov
@ 2022-01-13 7:41 ` Greg KH
2022-01-14 22:26 ` Iouri Tarassov
2022-01-14 18:03 ` Daniel Vetter
1 sibling, 1 reply; 33+ messages in thread
From: Greg KH @ 2022-01-13 7:41 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On Wed, Jan 12, 2022 at 11:55:14AM -0800, Iouri Tarassov wrote:
> Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile).
Your subject line does not describe what this is doing at all, as we
have no clue what DXGSYNCFILE is.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-01-13 7:41 ` Greg KH
@ 2022-01-14 22:26 ` Iouri Tarassov
0 siblings, 0 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-14 22:26 UTC (permalink / raw)
To: Greg KH
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On 1/12/2022 11:41 PM, Greg KH wrote:
> On Wed, Jan 12, 2022 at 11:55:14AM -0800, Iouri Tarassov wrote:
> > Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile).
>
> Your subject line does not describe what this is doing at all, as we
> have no clue what DXGSYNCFILE is.
Hi Greg,
I do not understand this comment. The full description is:
"
drivers: hv: dxgkrnl: Implement DXGSYNCFILE
Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile).
dxgsyncfile is built on top of the Linux sync_file object and
provides a way for the user mode to synchronize with the execution
of the device DMA packets.
The IOCTL creates a dxgsyncfile object for the given GPU synchronization
object and a fence value. A sync_object file descriptor is returned to
the caller. The caller could wait for the object by using poll().
When the GPU synchronization object is signaled on the host, the host
sends a message to the virtual machine and the sync_file object is
signaled.
"
Is this not enough?
Thanks
Iouri
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-01-12 19:55 ` [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE Iouri Tarassov
2022-01-13 7:41 ` Greg KH
@ 2022-01-14 18:03 ` Daniel Vetter
2022-01-14 18:52 ` Iouri Tarassov
1 sibling, 1 reply; 33+ messages in thread
From: Daniel Vetter @ 2022-01-14 18:03 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh, DRI Development, jenatali
Hi all,
On Wed, Jan 12, 2022 at 11:55:14AM -0800, Iouri Tarassov wrote:
> Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile).
>
> dxgsyncfile is built on top of the Linux sync_file object and
> provides a way for the user mode to synchronize with the execution
> of the device DMA packets.
>
> The IOCTL creates a dxgsyncfile object for the given GPU synchronization
> object and a fence value. A sync_object file descriptor is returned to
> the caller. The caller could wait for the object by using poll().
> When the GPU synchronization object is signaled on the host, the host
> sends a message to the virtual machine and the sync_file object is
> signaled.
>
> Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
Adding dri-devel, which get_maintainers.pl should have done automatically
with the dma_fence wildcard match. Not sure why that didn't happen.
> +struct dxgsyncpoint {
> + struct dxghostevent hdr;
> + struct dma_fence base;
This doesn't work unfortuntately. For better or worse memory fences like
monitored fences from wddm have completely different semantics from
dma_fence. You could probably hack this to be self-consistent for hyper-v,
but the problem is that then hv would have incompatible locking/nesting
rules compared to everything else, and dma_fence matter for memory
management so this includes whether you're allowed to kmalloc(GFP_KERNEL)
or not, and that's just a bit too much.
I discussed this quickly with Jesse on irc and it sounds like the reason
you want the dma_fence is just to emulate the sync_file interface for
android. I think the correct solution here is to create a hv_dxg_sync_file
fd, which emulates the exact ioctls that Android needs, but with a wddm
monitored fence underneath instead of a dma_fence underneath.
This way we guarantee that no one ever accidentally mixes these
incompatible concepts up in the kernel, and Android should still be able
to happily run under hyperv.
Thoughts?
Also pls cc me on this sync work since even if you drop dma_fence use
completely I'd like to follow this a bit.
Cheers, Daniel
> + u64 fence_value;
> + u64 context;
> + spinlock_t lock;
> + u64 u64;
> +};
> +
> +#endif /* _DXGSYNCFILE_H */
> diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
> index 773d8f364b34..185fb7e38c21 100644
> --- a/drivers/hv/dxgkrnl/dxgvmbus.c
> +++ b/drivers/hv/dxgkrnl/dxgvmbus.c
> @@ -1311,15 +1311,18 @@ int create_existing_sysmem(struct dxgdevice *device,
> void *kmem = NULL;
> int ret = 0;
> struct dxgkvmb_command_setexistingsysmemstore *set_store_command;
> + struct dxgkvmb_command_setexistingsysmempages *set_pages_command;
> u64 alloc_size = host_alloc->allocation_size;
> u32 npages = alloc_size >> PAGE_SHIFT;
> struct dxgvmbusmsg msg = {.hdr = NULL};
> -
> - ret = init_message(&msg, device->adapter, device->process,
> - sizeof(*set_store_command));
> - if (ret)
> - goto cleanup;
> - set_store_command = (void *)msg.msg;
> + const u32 max_pfns_in_message =
> + (DXG_MAX_VM_BUS_PACKET_SIZE - sizeof(*set_pages_command) -
> + PAGE_SIZE) / sizeof(__u64);
> + u32 alloc_offset_in_pages = 0;
> + struct page **page_in;
> + u64 *pfn;
> + u32 pages_to_send;
> + u32 i;
>
> /*
> * Create a guest physical address list and set it as the allocation
> @@ -1330,6 +1333,7 @@ int create_existing_sysmem(struct dxgdevice *device,
> dev_dbg(dxgglobaldev, " Alloc size: %lld", alloc_size);
>
> dxgalloc->cpu_address = (void *)sysmem;
> +
> dxgalloc->pages = vzalloc(npages * sizeof(void *));
> if (dxgalloc->pages == NULL) {
> pr_err("failed to allocate pages");
> @@ -1347,31 +1351,80 @@ int create_existing_sysmem(struct dxgdevice *device,
> ret = -ENOMEM;
> goto cleanup;
> }
> - kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
> - if (kmem == NULL) {
> - pr_err("vmap failed");
> - ret = -ENOMEM;
> - goto cleanup;
> - }
> - ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
> - alloc_size, &dxgalloc->gpadl);
> - if (ret1) {
> - pr_err("establish_gpadl failed: %d", ret1);
> - ret = -ENOMEM;
> - goto cleanup;
> - }
> - dev_dbg(dxgglobaldev, "New gpadl %d", dxgalloc->gpadl.gpadl_handle);
> + if (!dxgglobal->map_guest_pages_enabled) {
> + ret = init_message(&msg, device->adapter, device->process,
> + sizeof(*set_store_command));
> + if (ret)
> + goto cleanup;
> + set_store_command = (void *)msg.msg;
>
> - command_vgpu_to_host_init2(&set_store_command->hdr,
> - DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
> - device->process->host_handle);
> - set_store_command->device = device->handle;
> - set_store_command->device = device->handle;
> - set_store_command->allocation = host_alloc->allocation;
> - set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
> - ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
> - if (ret < 0)
> - pr_err("failed to set existing store: %x", ret);
> + kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
> + if (kmem == NULL) {
> + pr_err("vmap failed");
> + ret = -ENOMEM;
> + goto cleanup;
> + }
> + ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
> + alloc_size, &dxgalloc->gpadl);
> + if (ret1) {
> + pr_err("establish_gpadl failed: %d", ret1);
> + ret = -ENOMEM;
> + goto cleanup;
> + }
> + dev_dbg(dxgglobaldev, "New gpadl %d",
> + dxgalloc->gpadl.gpadl_handle);
> +
> + command_vgpu_to_host_init2(&set_store_command->hdr,
> + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
> + device->process->host_handle);
> + set_store_command->device = device->handle;
> + set_store_command->allocation = host_alloc->allocation;
> + set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
> + ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
> + msg.size);
> + if (ret < 0)
> + pr_err("failed to set existing store: %x", ret);
> + } else {
> + /*
> + * Send the list of the allocation PFNs to the host. The host
> + * will map the pages for GPU access.
> + */
> +
> + ret = init_message(&msg, device->adapter, device->process,
> + sizeof(*set_pages_command) +
> + max_pfns_in_message * sizeof(u64));
> + if (ret)
> + goto cleanup;
> + set_pages_command = (void *)msg.msg;
> + command_vgpu_to_host_init2(&set_pages_command->hdr,
> + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES,
> + device->process->host_handle);
> + set_pages_command->device = device->handle;
> + set_pages_command->allocation = host_alloc->allocation;
> +
> + page_in = dxgalloc->pages;
> + while (alloc_offset_in_pages < npages) {
> + pfn = (u64 *)((char *)msg.msg +
> + sizeof(*set_pages_command));
> + pages_to_send = min(npages - alloc_offset_in_pages,
> + max_pfns_in_message);
> + set_pages_command->num_pages = pages_to_send;
> + set_pages_command->alloc_offset_in_pages =
> + alloc_offset_in_pages;
> +
> + for (i = 0; i < pages_to_send; i++)
> + *pfn++ = page_to_pfn(*page_in++);
> +
> + ret = dxgvmb_send_sync_msg_ntstatus(msg.channel,
> + msg.hdr,
> + msg.size);
> + if (ret < 0) {
> + pr_err("failed to set existing pages: %x", ret);
> + break;
> + }
> + alloc_offset_in_pages += pages_to_send;
> + }
> + }
>
> cleanup:
> if (kmem)
> @@ -2685,6 +2738,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
> struct
> d3dkmt_waitforsynchronizationobjectfromcpu
> *args,
> + bool user_address,
> u64 cpu_event)
> {
> int ret = -EINVAL;
> @@ -2708,18 +2762,25 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
> 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) {
> - pr_err("%s failed to copy objects", __func__);
> - ret = -EINVAL;
> - goto cleanup;
> - }
> - current_pos += object_size;
> - ret = copy_from_user(current_pos, args->fence_values, fence_size);
> - if (ret) {
> - pr_err("%s failed to copy fences", __func__);
> - ret = -EINVAL;
> - goto cleanup;
> + if (user_address) {
> + ret = copy_from_user(current_pos, args->objects, object_size);
> + if (ret) {
> + pr_err("%s failed to copy objects", __func__);
> + ret = -EINVAL;
> + goto cleanup;
> + }
> + current_pos += object_size;
> + ret = copy_from_user(current_pos, args->fence_values,
> + fence_size);
> + if (ret) {
> + pr_err("%s failed to copy fences", __func__);
> + ret = -EINVAL;
> + goto cleanup;
> + }
> + } else {
> + memcpy(current_pos, args->objects, object_size);
> + current_pos += object_size;
> + memcpy(current_pos, args->fence_values, fence_size);
> }
>
> ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
> diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
> index a19ac804a320..dc766d95a0c4 100644
> --- a/drivers/hv/dxgkrnl/dxgvmbus.h
> +++ b/drivers/hv/dxgkrnl/dxgvmbus.h
> @@ -139,6 +139,8 @@ enum dxgkvmb_commandtype {
> DXGK_VMBCOMMAND_GETCONTEXTSCHEDULINGPRIORITY = 61,
> DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION = 62,
> DXGK_VMBCOMMAND_QUERYRESOURCEINFO = 64,
> + DXGK_VMBCOMMAND_LOGEVENT = 65,
> + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES = 66,
> DXGK_VMBCOMMAND_INVALID
> };
>
> @@ -245,6 +247,16 @@ struct dxgkvmb_command_setexistingsysmemstore {
> u32 gpadl;
> };
>
> +/* Returns ntstatus */
> +struct dxgkvmb_command_setexistingsysmempages {
> + struct dxgkvmb_command_vgpu_to_host hdr;
> + struct d3dkmthandle device;
> + struct d3dkmthandle allocation;
> + u32 num_pages;
> + u32 alloc_offset_in_pages;
> + /* u64 pfn_array[num_pages] */
> +};
> +
> struct dxgkvmb_command_createprocess {
> struct dxgkvmb_command_vm_to_host hdr;
> void *process;
> diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
> index 9770fabf163e..9236b6b95973 100644
> --- a/drivers/hv/dxgkrnl/ioctl.c
> +++ b/drivers/hv/dxgkrnl/ioctl.c
> @@ -19,6 +19,7 @@
>
> #include "dxgkrnl.h"
> #include "dxgvmbus.h"
> +#include "dxgsyncfile.h"
>
> #undef pr_fmt
> #define pr_fmt(fmt) "dxgk:err: " fmt
> @@ -32,11 +33,6 @@ struct ioctl_desc {
> };
> static struct ioctl_desc ioctls[LX_IO_MAX + 1];
>
> -static char *errorstr(int ret)
> -{
> - return ret < 0 ? "err" : "";
> -}
> -
> static int dxgsyncobj_release(struct inode *inode, struct file *file)
> {
> struct dxgsharedsyncobject *syncobj = file->private_data;
> @@ -3561,7 +3557,7 @@ dxgk_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
> }
>
> ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
> - &args, event_id);
> + &args, true, event_id);
> if (ret < 0)
> goto cleanup;
>
> @@ -5457,4 +5453,6 @@ void init_ioctls(void)
> LX_DXQUERYSTATISTICS);
> SET_IOCTL(/*0x44 */ dxgk_share_object_with_host,
> LX_DXSHAREOBJECTWITHHOST);
> + SET_IOCTL(/*0x45 */ dxgk_create_sync_file,
> + LX_DXCREATESYNCFILE);
> }
> diff --git a/drivers/hv/dxgkrnl/misc.c b/drivers/hv/dxgkrnl/misc.c
> index ffb491641836..1b152c269265 100644
> --- a/drivers/hv/dxgkrnl/misc.c
> +++ b/drivers/hv/dxgkrnl/misc.c
> @@ -35,3 +35,9 @@ u16 *wcsncpy(u16 *dest, const u16 *src, size_t n)
> dest[i - 1] = 0;
> return dest;
> }
> +
> +char *errorstr(int ret)
> +{
> + return ret < 0 ? "err" : "";
> +}
> +
> diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h
> index 7fe3fc45b67c..3079dd55c7a4 100644
> --- a/drivers/hv/dxgkrnl/misc.h
> +++ b/drivers/hv/dxgkrnl/misc.h
> @@ -44,6 +44,7 @@ extern const struct d3dkmthandle zerohandle;
> */
>
> u16 *wcsncpy(u16 *dest, const u16 *src, size_t n);
> +char *errorstr(int ret);
>
> enum dxglockstate {
> DXGLOCK_SHARED,
> --
> 2.32.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-01-14 18:03 ` Daniel Vetter
@ 2022-01-14 18:52 ` Iouri Tarassov
2022-01-17 9:35 ` Daniel Vetter
0 siblings, 1 reply; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-14 18:52 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh, DRI Development, jenatali
On 1/14/2022 10:03 AM, Daniel Vetter wrote:
> Hi all,
>
> On Wed, Jan 12, 2022 at 11:55:14AM -0800, Iouri Tarassov wrote:
> > Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile).
> >
> > dxgsyncfile is built on top of the Linux sync_file object and
> > provides a way for the user mode to synchronize with the execution
> > of the device DMA packets.
> >
> > The IOCTL creates a dxgsyncfile object for the given GPU synchronization
> > object and a fence value. A sync_object file descriptor is returned to
> > the caller. The caller could wait for the object by using poll().
> > When the GPU synchronization object is signaled on the host, the host
> > sends a message to the virtual machine and the sync_file object is
> > signaled.
> >
> > Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
>
> Adding dri-devel, which get_maintainers.pl should have done automatically
> with the dma_fence wildcard match. Not sure why that didn't happen.
>
> > +struct dxgsyncpoint {
> > + struct dxghostevent hdr;
> > + struct dma_fence base;
>
> This doesn't work unfortuntately. For better or worse memory fences like
> monitored fences from wddm have completely different semantics from
> dma_fence. You could probably hack this to be self-consistent for hyper-v,
> but the problem is that then hv would have incompatible locking/nesting
> rules compared to everything else, and dma_fence matter for memory
> management so this includes whether you're allowed to kmalloc(GFP_KERNEL)
> or not, and that's just a bit too much.
>
> I discussed this quickly with Jesse on irc and it sounds like the reason
> you want the dma_fence is just to emulate the sync_file interface for
> android. I think the correct solution here is to create a hv_dxg_sync_file
> fd, which emulates the exact ioctls that Android needs, but with a wddm
> monitored fence underneath instead of a dma_fence underneath.
>
> This way we guarantee that no one ever accidentally mixes these
> incompatible concepts up in the kernel, and Android should still be able
> to happily run under hyperv.
>
> Thoughts?
>
> Also pls cc me on this sync work since even if you drop dma_fence use
> completely I'd like to follow this a bit.
Hi Daniel,
Thank you for the review and feedback.
I will get this addressed.
Iouri
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-01-14 18:52 ` Iouri Tarassov
@ 2022-01-17 9:35 ` Daniel Vetter
2022-02-05 0:35 ` Iouri Tarassov
0 siblings, 1 reply; 33+ messages in thread
From: Daniel Vetter @ 2022-01-17 9:35 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh, DRI Development, jenatali
On Mon, Jan 17, 2022 at 9:34 AM Iouri Tarassov
<iourit@linux.microsoft.com> wrote:
>
>
> On 1/14/2022 10:03 AM, Daniel Vetter wrote:
> > Hi all,
> >
> > On Wed, Jan 12, 2022 at 11:55:14AM -0800, Iouri Tarassov wrote:
> > > Implement the LX_DXCREATESYNCFILE IOCTL (D3DKMTCreateSyncFile).
> > >
> > > dxgsyncfile is built on top of the Linux sync_file object and
> > > provides a way for the user mode to synchronize with the execution
> > > of the device DMA packets.
> > >
> > > The IOCTL creates a dxgsyncfile object for the given GPU synchronization
> > > object and a fence value. A sync_object file descriptor is returned to
> > > the caller. The caller could wait for the object by using poll().
> > > When the GPU synchronization object is signaled on the host, the host
> > > sends a message to the virtual machine and the sync_file object is
> > > signaled.
> > >
> > > Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
> >
> > Adding dri-devel, which get_maintainers.pl should have done automatically
> > with the dma_fence wildcard match. Not sure why that didn't happen.
> >
> > > +struct dxgsyncpoint {
> > > + struct dxghostevent hdr;
> > > + struct dma_fence base;
> >
> > This doesn't work unfortuntately. For better or worse memory fences like
> > monitored fences from wddm have completely different semantics from
> > dma_fence. You could probably hack this to be self-consistent for hyper-v,
> > but the problem is that then hv would have incompatible locking/nesting
> > rules compared to everything else, and dma_fence matter for memory
> > management so this includes whether you're allowed to kmalloc(GFP_KERNEL)
> > or not, and that's just a bit too much.
> >
> > I discussed this quickly with Jesse on irc and it sounds like the reason
> > you want the dma_fence is just to emulate the sync_file interface for
> > android. I think the correct solution here is to create a hv_dxg_sync_file
> > fd, which emulates the exact ioctls that Android needs, but with a wddm
> > monitored fence underneath instead of a dma_fence underneath.
> >
> > This way we guarantee that no one ever accidentally mixes these
> > incompatible concepts up in the kernel, and Android should still be able
> > to happily run under hyperv.
> >
> > Thoughts?
> >
> > Also pls cc me on this sync work since even if you drop dma_fence use
> > completely I'd like to follow this a bit.
>
> Hi Daniel,
>
> Thank you for the review and feedback.
> I will get this addressed.
btw another idea I had over the w/e: Another option might be to allow
different backends for sync_file, and then making sure that you cannot
ever mix dma_fence and hv_dxg_fence type sync_file up (in e.g. the
merge ioctl).
The issue is that fundamentally dma_fence and memory fences (or umf
for userspace memory fences as we tend to call them) aren't
compatible, but some of the interop plans we have is to allow stuffing
either of them into fence container objects like sync_file. So going
that route for wddm monitored fence support too could be a really
future-proof approach, plus it'd allow you to still share the
sync_file interface code. Not that it's going to be much code sharing,
since all the implementation code needs to be distinct.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-01-17 9:35 ` Daniel Vetter
@ 2022-02-05 0:35 ` Iouri Tarassov
2022-02-08 12:28 ` Daniel Vetter
0 siblings, 1 reply; 33+ messages in thread
From: Iouri Tarassov @ 2022-02-05 0:35 UTC (permalink / raw)
To: Daniel Vetter
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh, DRI Development, jenatali
On 1/17/2022 1:35 AM, Daniel Vetter wrote:
> On Mon, Jan 17, 2022 at 9:34 AM Iouri Tarassov
> <iourit@linux.microsoft.com> wrote:
> >
> >
> btw another idea I had over the w/e: Another option might be to allow
> different backends for sync_file, and then making sure that you cannot
> ever mix dma_fence and hv_dxg_fence type sync_file up (in e.g. the
> merge ioctl).
>
> The issue is that fundamentally dma_fence and memory fences (or umf
> for userspace memory fences as we tend to call them) aren't
> compatible, but some of the interop plans we have is to allow stuffing
> either of them into fence container objects like sync_file. So going
> that route for wddm monitored fence support too could be a really
> future-proof approach, plus it'd allow you to still share the
> sync_file interface code. Not that it's going to be much code sharing,
> since all the implementation code needs to be distinct.
> -Daniel
Thanks Daniel!
I will remove the patch for dxgsyncfile from the next set of upstream
patches.
It will be added later after a re-design.
Iouri
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE
2022-02-05 0:35 ` Iouri Tarassov
@ 2022-02-08 12:28 ` Daniel Vetter
0 siblings, 0 replies; 33+ messages in thread
From: Daniel Vetter @ 2022-02-08 12:28 UTC (permalink / raw)
To: Iouri Tarassov
Cc: Daniel Vetter, kys, haiyangz, sthemmin, wei.liu, linux-hyperv,
linux-kernel, spronovo, gregkh, DRI Development, jenatali
On Fri, Feb 04, 2022 at 04:35:55PM -0800, Iouri Tarassov wrote:
>
> On 1/17/2022 1:35 AM, Daniel Vetter wrote:
> > On Mon, Jan 17, 2022 at 9:34 AM Iouri Tarassov
> > <iourit@linux.microsoft.com> wrote:
> > >
> > >
> > btw another idea I had over the w/e: Another option might be to allow
> > different backends for sync_file, and then making sure that you cannot
> > ever mix dma_fence and hv_dxg_fence type sync_file up (in e.g. the
> > merge ioctl).
> >
> > The issue is that fundamentally dma_fence and memory fences (or umf
> > for userspace memory fences as we tend to call them) aren't
> > compatible, but some of the interop plans we have is to allow stuffing
> > either of them into fence container objects like sync_file. So going
> > that route for wddm monitored fence support too could be a really
> > future-proof approach, plus it'd allow you to still share the
> > sync_file interface code. Not that it's going to be much code sharing,
> > since all the implementation code needs to be distinct.
> > -Daniel
>
> Thanks Daniel!
>
> I will remove the patch for dxgsyncfile from the next set of upstream
> patches.
>
> It will be added later after a re-design.
Yeah sounds like a good plan forward to not hold up everything else
meanwhile.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview
2022-01-12 19:55 [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Iouri Tarassov
` (7 preceding siblings ...)
2022-01-12 19:55 ` [PATCH v1 9/9] drivers: hv: dxgkrnl: Implement DXGSYNCFILE Iouri Tarassov
@ 2022-01-12 22:12 ` Nathan Chancellor
2022-01-12 23:39 ` Iouri Tarassov
[not found] ` <1b26482b50832b95a9d8532c493cee6c97323b87.1641937419.git.iourit@linux.microsoft.com>
9 siblings, 1 reply; 33+ messages in thread
From: Nathan Chancellor @ 2022-01-12 22:12 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh
Hi Iouri,
On Wed, Jan 12, 2022 at 11:55:05AM -0800, Iouri Tarassov wrote:
> This is a follow-up on the changes we sent a few months back[1].
>
> [1] https://lore.kernel.org/lkml/20200814123856.3880009-1-sashal@kernel.org/
>
> The patches address the feedback, given by Greg KH and other reviewers, contain
> bug fixes, the implementation of asynchronous VM bus messages to the host
> and contain the remaining implementation of our vGPU / Compute hardware
> virtualization support that powers the Windows Subsystem for Linux (WSL) and
> will soon power the Windows Subsystem for Android (WSA).
<snip>
> We're looking forward additional feedback.
I have been including this patch set into my downstream WSL2 kernel that
I build with clang and I noticed an instance of -Wenum-conversion that
is still present in this revision:
In file included from drivers/hv/dxgkrnl/dxgsyncfile.c:21:
drivers/hv/dxgkrnl/dxgvmbus.h:894:26: warning: implicit conversion from enumeration type 'enum dxgkvmb_commandtype' to different enumeration type 'enum dxgkvmb_commandtype_global' [-Wenum-conversion]
command->command_type = DXGK_VMBCOMMAND_INVALID;
~ ^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
In file included from drivers/hv/dxgkrnl/dxgvmbus.c:23:
drivers/hv/dxgkrnl/dxgvmbus.h:894:26: warning: implicit conversion from enumeration type 'enum dxgkvmb_commandtype' to different enumeration type 'enum dxgkvmb_commandtype_global' [-Wenum-conversion]
command->command_type = DXGK_VMBCOMMAND_INVALID;
~ ^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
In file included from drivers/hv/dxgkrnl/ioctl.c:21:
drivers/hv/dxgkrnl/dxgvmbus.h:894:26: warning: implicit conversion from enumeration type 'enum dxgkvmb_commandtype' to different enumeration type 'enum dxgkvmb_commandtype_global' [-Wenum-conversion]
command->command_type = DXGK_VMBCOMMAND_INVALID;
~ ^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
This comes from command_vgpu_to_host_init0(), which does not actually
appear to be used anywhere:
$ rg command_vgpu_to_host_init0
drivers/hv/dxgkrnl/dxgvmbus.h
891:static inline void command_vgpu_to_host_init0(struct dxgkvmb_command_vm_to_host
Please consider cleaning this up in a future revision so that clang
builds stay clean :)
I happened to notice there was another function that looks very similar
to command_vgpu_to_host_init0(), command_vm_to_host_init0(), which is
also unused. This was hidden because it is marked as "static inline" in
a .c file, which should generally be avoided; I would recommend
replacing all instances of "static inline" with just "static". The
compiler will still inline it if it feels it is worthwhile. Doing this
reveals one other unused function, is_empty():
$ sed -i 's/static inline /static /g' drivers/hv/dxgkrnl/*.c
$ make -skj"$(nproc)" LLVM=1 drivers/hv/dxgkrnl/
drivers/hv/dxgkrnl/hmgr.c:167:13: warning: unused function 'is_empty' [-Wunused-function]
static bool is_empty(struct hmgrtable *table)
^
1 warning generated.
drivers/hv/dxgkrnl/dxgvmbus.c:234:13: warning: unused function 'command_vm_to_host_init0' [-Wunused-function]
static void command_vm_to_host_init0(struct dxgkvmb_command_vm_to_host
^
1 warning generated.
Cheers,
Nathan
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview
2022-01-12 22:12 ` [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview Nathan Chancellor
@ 2022-01-12 23:39 ` Iouri Tarassov
2022-01-26 0:27 ` Nathan Chancellor
0 siblings, 1 reply; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-12 23:39 UTC (permalink / raw)
To: Nathan Chancellor
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh
On 1/12/2022 2:12 PM, Nathan Chancellor wrote:
> Hi Iouri,
>
> > We're looking forward additional feedback.
>
> I have been including this patch set into my downstream WSL2 kernel that
> I build with clang and I noticed an instance of -Wenum-conversion that
> is still present in this revision:Please consider cleaning this up in a future revision so that clang
> builds stay clean :)
> ...
> I happened to notice there was another function that looks very similar
> to command_vgpu_to_host_init0(), command_vm_to_host_init0(), which is
> also unused. This was hidden because it is marked as "static inline" in
> a .c file, which should generally be avoided; I would recommend
> replacing all instances of "static inline" with just "static". The
> compiler will still inline it if it feels it is worthwhile. Doing this
> reveals one other unused function, is_empty():
>
> $ sed -i 's/static inline /static /g' drivers/hv/dxgkrnl/*.c
>
> $ make -skj"$(nproc)" LLVM=1 drivers/hv/dxgkrnl/
> drivers/hv/dxgkrnl/hmgr.c:167:13: warning: unused function 'is_empty' [-Wunused-function]
> static bool is_empty(struct hmgrtable *table)
> ^
> 1 warning generated.
> drivers/hv/dxgkrnl/dxgvmbus.c:234:13: warning: unused function 'command_vm_to_host_init0' [-Wunused-function]
> static void command_vm_to_host_init0(struct dxgkvmb_command_vm_to_host
> ^
> 1 warning generated.
Hi Nathan,
Thanks a lot! We will get this fixed
Iouri
> Cheers,
> Nathan
>
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview
2022-01-12 23:39 ` Iouri Tarassov
@ 2022-01-26 0:27 ` Nathan Chancellor
2022-02-05 0:31 ` Iouri Tarassov
0 siblings, 1 reply; 33+ messages in thread
From: Nathan Chancellor @ 2022-01-26 0:27 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh
Hi Iouri,
On Wed, Jan 12, 2022 at 03:39:13PM -0800, Iouri Tarassov wrote:
>
> On 1/12/2022 2:12 PM, Nathan Chancellor wrote:
> > Hi Iouri,
> >
> > > We're looking forward additional feedback.
> >
> > I have been including this patch set into my downstream WSL2 kernel that
> > I build with clang and I noticed an instance of -Wenum-conversion that
> > is still present in this revision:Please consider cleaning this up in a future revision so that clang
> > builds stay clean :)
> > ...
> > I happened to notice there was another function that looks very similar
> > to command_vgpu_to_host_init0(), command_vm_to_host_init0(), which is
> > also unused. This was hidden because it is marked as "static inline" in
> > a .c file, which should generally be avoided; I would recommend
> > replacing all instances of "static inline" with just "static". The
> > compiler will still inline it if it feels it is worthwhile. Doing this
> > reveals one other unused function, is_empty():
> >
> > $ sed -i 's/static inline /static /g' drivers/hv/dxgkrnl/*.c
> >
> > $ make -skj"$(nproc)" LLVM=1 drivers/hv/dxgkrnl/
> > drivers/hv/dxgkrnl/hmgr.c:167:13: warning: unused function 'is_empty' [-Wunused-function]
> > static bool is_empty(struct hmgrtable *table)
> > ^
> > 1 warning generated.
> > drivers/hv/dxgkrnl/dxgvmbus.c:234:13: warning: unused function 'command_vm_to_host_init0' [-Wunused-function]
> > static void command_vm_to_host_init0(struct dxgkvmb_command_vm_to_host
> > ^
> > 1 warning generated.
>
> Thanks a lot! We will get this fixed
In addition to the warnings that I mentioned above, when I apply this
patchset on top of next-20220125, which enables -Warray-bounds, I see
the following warnings with GCC 11.2.1:
drivers/hv/dxgkrnl/ioctl.c: In function ‘init_ioctls’:
drivers/hv/dxgkrnl/ioctl.c:5315:15: warning: array subscript 69 is above array bounds of ‘struct ioctl_desc[69]’ [-Warray-bounds]
5315 | ioctls[_IOC_NR(v)].ioctl_callback = callback; \
| ~~~~~~^~~~~~~~~~~~
drivers/hv/dxgkrnl/ioctl.c:5456:9: note: in expansion of macro ‘SET_IOCTL’
5456 | SET_IOCTL(/*0x45 */ dxgk_create_sync_file,
| ^~~~~~~~~
drivers/hv/dxgkrnl/ioctl.c:34:26: note: while referencing ‘ioctls’
34 | static struct ioctl_desc ioctls[LX_IO_MAX + 1];
| ^~~~~~
drivers/hv/dxgkrnl/ioctl.c:5316:15: warning: array subscript 69 is above array bounds of ‘struct ioctl_desc[69]’ [-Warray-bounds]
5316 | ioctls[_IOC_NR(v)].ioctl = v
| ~~~~~~^~~~~~~~~~~~
drivers/hv/dxgkrnl/ioctl.c:5456:9: note: in expansion of macro ‘SET_IOCTL’
5456 | SET_IOCTL(/*0x45 */ dxgk_create_sync_file,
| ^~~~~~~~~
drivers/hv/dxgkrnl/ioctl.c:34:26: note: while referencing ‘ioctls’
34 | static struct ioctl_desc ioctls[LX_IO_MAX + 1];
| ^~~~~~
drivers/hv/dxgkrnl/dxgvmbus.c: In function ‘dxgvmb_send_query_alloc_residency’:
drivers/hv/dxgkrnl/dxgvmbus.c:147:16: warning: array subscript ‘struct dxgvmbusmsg[0]’ is partly outside array bounds of ‘struct dxgvmbusmsgres[1]’ [-Warray-bounds]
147 | if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
| ~~~^~~~~
drivers/hv/dxgkrnl/dxgvmbus.c:1882:31: note: while referencing ‘msg’
1882 | struct dxgvmbusmsgres msg = {.hdr = NULL};
| ^~~
drivers/hv/dxgkrnl/dxgvmbus.c: In function ‘dxgvmb_send_open_resource’:
drivers/hv/dxgkrnl/dxgvmbus.c:147:16: warning: array subscript ‘struct dxgvmbusmsg[0]’ is partly outside array bounds of ‘struct dxgvmbusmsgres[1]’ [-Warray-bounds]
147 | if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
| ~~~^~~~~
drivers/hv/dxgkrnl/dxgvmbus.c:2132:31: note: while referencing ‘msg’
2132 | struct dxgvmbusmsgres msg = {.hdr = NULL};
| ^~~
drivers/hv/dxgkrnl/dxgvmbus.c: In function ‘dxgvmb_send_get_stdalloc_data’:
drivers/hv/dxgkrnl/dxgvmbus.c:147:16: warning: array subscript ‘struct dxgvmbusmsg[0]’ is partly outside array bounds of ‘struct dxgvmbusmsgres[1]’ [-Warray-bounds]
147 | if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
| ~~~^~~~~
drivers/hv/dxgkrnl/dxgvmbus.c:2183:31: note: while referencing ‘msg’
2183 | struct dxgvmbusmsgres msg = {.hdr = NULL};
| ^~~
drivers/hv/dxgkrnl/dxgvmbus.c: In function ‘dxgvmb_send_get_allocation_priority’:
drivers/hv/dxgkrnl/dxgvmbus.c:147:16: warning: array subscript ‘struct dxgvmbusmsg[0]’ is partly outside array bounds of ‘struct dxgvmbusmsgres[1]’ [-Warray-bounds]
147 | if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
| ~~~^~~~~
drivers/hv/dxgkrnl/dxgvmbus.c:3106:31: note: while referencing ‘msg’
3106 | struct dxgvmbusmsgres msg = {.hdr = NULL};
| ^~~
drivers/hv/dxgkrnl/dxgvmbus.c: In function ‘dxgvmb_send_reclaim_allocations’:
drivers/hv/dxgkrnl/dxgvmbus.c:147:16: warning: array subscript ‘struct dxgvmbusmsg[0]’ is partly outside array bounds of ‘struct dxgvmbusmsgres[1]’ [-Warray-bounds]
147 | if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
| ~~~^~~~~
drivers/hv/dxgkrnl/dxgvmbus.c:3298:31: note: while referencing ‘msg’
3298 | struct dxgvmbusmsgres msg = {.hdr = NULL};
| ^~~
drivers/hv/dxgkrnl/dxgvmbus.c: In function ‘dxgvmb_send_query_statistics’:
drivers/hv/dxgkrnl/dxgvmbus.c:147:16: warning: array subscript ‘struct dxgvmbusmsg[0]’ is partly outside array bounds of ‘struct dxgvmbusmsgres[1]’ [-Warray-bounds]
147 | if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
| ~~~^~~~~
drivers/hv/dxgkrnl/dxgvmbus.c:3698:31: note: while referencing ‘msg’
3698 | struct dxgvmbusmsgres msg = {.hdr = NULL};
| ^~~
The warning in ioctl.c is resolved with the following diff, which
appears to be a forward port problem, since the WSL2 tree is fine. I
don't see the warning in dxgvmbus.c with clang so I did not look into
it.
Cheers,
Nathan
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index a7c9fdd95e2e..a32431e3df56 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -1949,6 +1949,6 @@ struct d3dkmt_createsyncfile {
#define LX_DXCREATESYNCFILE \
_IOWR(0x47, 0x45, struct d3dkmt_createsyncfile)
-#define LX_IO_MAX 0x44
+#define LX_IO_MAX 0x45
#endif /* _D3DKMTHK_H */
^ permalink raw reply related [flat|nested] 33+ messages in thread* Re: [PATCH v1 0/9] drivers: hv: dxgkrnl: Driver overview
2022-01-26 0:27 ` Nathan Chancellor
@ 2022-02-05 0:31 ` Iouri Tarassov
0 siblings, 0 replies; 33+ messages in thread
From: Iouri Tarassov @ 2022-02-05 0:31 UTC (permalink / raw)
To: Nathan Chancellor
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo, gregkh
On 1/25/2022 4:27 PM, Nathan Chancellor wrote:
> Hi Iouri,
>
> On Wed, Jan 12, 2022 at 03:39:13PM -0800, Iouri Tarassov wrote:
> >
> drivers/hv/dxgkrnl/dxgvmbus.c: In function ‘dxgvmb_send_query_alloc_residency’:
> drivers/hv/dxgkrnl/dxgvmbus.c:147:16: warning: array subscript ‘struct dxgvmbusmsg[0]’ is partly outside array bounds of ‘struct dxgvmbusmsgres[1]’ [-Warray-bounds]
> 147 | if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
> | ~~~^~~~~
> drivers/hv/dxgkrnl/dxgvmbus.c:1882:31: note: while referencing ‘msg’
> 1882 | struct dxgvmbusmsgres msg = {.hdr = NULL};
> | ^~~
Hi Nathan,
I fixed the issue with the ioctls array.
Regarding the warning above, it looks like a compiler error. I do not
see where the out of bounds access is.
I tried GCC-11 version 11.2.0 and this warning is not there.
Thanks
Iouri
^ permalink raw reply [flat|nested] 33+ messages in thread
[parent not found: <1b26482b50832b95a9d8532c493cee6c97323b87.1641937419.git.iourit@linux.microsoft.com>]
* Re: [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
[not found] ` <1b26482b50832b95a9d8532c493cee6c97323b87.1641937419.git.iourit@linux.microsoft.com>
@ 2022-01-13 1:49 ` kernel test robot
2022-01-13 6:42 ` kernel test robot
` (2 subsequent siblings)
3 siblings, 0 replies; 33+ messages in thread
From: kernel test robot @ 2022-01-13 1:49 UTC (permalink / raw)
To: Iouri Tarassov, kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: kbuild-all, linux-kernel, spronovo, gregkh
Hi Iouri,
I love your patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v5.16 next-20220112]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git e3084ed48fd6b661fe434da0cb36d7d6706cf27f
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20220113/202201130941.ZVnyqikS-lkp@intel.com/config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
# https://github.com/0day-ci/linux/commit/00f97c12e2cf0ba4ba1108e2fce9a3d0e287cc8c
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
git checkout 00f97c12e2cf0ba4ba1108e2fce9a3d0e287cc8c
# save the config file to linux build tree
mkdir build_dir
make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/hv/dxgkrnl/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> drivers/hv/dxgkrnl/dxgmodule.c:79:20: warning: no previous prototype for 'find_pci_adapter' [-Wmissing-prototypes]
79 | struct dxgadapter *find_pci_adapter(struct pci_dev *dev)
| ^~~~~~~~~~~~~~~~
>> drivers/hv/dxgkrnl/dxgmodule.c:135:6: warning: no previous prototype for 'signal_host_cpu_event' [-Wmissing-prototypes]
135 | void signal_host_cpu_event(struct dxghostevent *eventhdr)
| ^~~~~~~~~~~~~~~~~~~~~
>> drivers/hv/dxgkrnl/dxgmodule.c:219:5: warning: no previous prototype for 'dxgglobal_create_adapter' [-Wmissing-prototypes]
219 | int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
| ^~~~~~~~~~~~~~~~~~~~~~~~
--
>> drivers/hv/dxgkrnl/dxgvmbus.c:116:5: warning: no previous prototype for 'ntstatus2int' [-Wmissing-prototypes]
116 | int ntstatus2int(struct ntstatus status)
| ^~~~~~~~~~~~
>> drivers/hv/dxgkrnl/dxgvmbus.c:219:6: warning: no previous prototype for 'process_inband_packet' [-Wmissing-prototypes]
219 | void process_inband_packet(struct dxgvmbuschannel *channel,
| ^~~~~~~~~~~~~~~~~~~~~
>> drivers/hv/dxgkrnl/dxgvmbus.c:237:6: warning: no previous prototype for 'process_completion_packet' [-Wmissing-prototypes]
237 | void process_completion_packet(struct dxgvmbuschannel *channel,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/hv/dxgkrnl/dxgvmbus.c:363:5: warning: no previous prototype for 'dxgvmb_send_async_msg' [-Wmissing-prototypes]
363 | int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
| ^~~~~~~~~~~~~~~~~~~~~
vim +/find_pci_adapter +79 drivers/hv/dxgkrnl/dxgmodule.c
78
> 79 struct dxgadapter *find_pci_adapter(struct pci_dev *dev)
80 {
81 struct dxgadapter *entry;
82 struct dxgadapter *adapter = NULL;
83
84 dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL);
85
86 list_for_each_entry(entry, &dxgglobal->adapter_list_head,
87 adapter_list_entry) {
88 if (dev == entry->pci_dev) {
89 adapter = entry;
90 break;
91 }
92 }
93
94 dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL);
95 return adapter;
96 }
97
98 static struct dxgadapter *find_adapter(struct winluid *luid)
99 {
100 struct dxgadapter *entry;
101 struct dxgadapter *adapter = NULL;
102
103 dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL);
104
105 list_for_each_entry(entry, &dxgglobal->adapter_list_head,
106 adapter_list_entry) {
107 if (memcmp(luid, &entry->luid, sizeof(struct winluid)) == 0) {
108 adapter = entry;
109 break;
110 }
111 }
112
113 dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL);
114 return adapter;
115 }
116
117 void dxgglobal_add_host_event(struct dxghostevent *event)
118 {
119 spin_lock_irq(&dxgglobal->host_event_list_mutex);
120 list_add_tail(&event->host_event_list_entry,
121 &dxgglobal->host_event_list_head);
122 spin_unlock_irq(&dxgglobal->host_event_list_mutex);
123 }
124
125 void dxgglobal_remove_host_event(struct dxghostevent *event)
126 {
127 spin_lock_irq(&dxgglobal->host_event_list_mutex);
128 if (event->host_event_list_entry.next != NULL) {
129 list_del(&event->host_event_list_entry);
130 event->host_event_list_entry.next = NULL;
131 }
132 spin_unlock_irq(&dxgglobal->host_event_list_mutex);
133 }
134
> 135 void signal_host_cpu_event(struct dxghostevent *eventhdr)
136 {
137 struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
138
139 if (event->remove_from_list ||
140 event->destroy_after_signal) {
141 list_del(&eventhdr->host_event_list_entry);
142 eventhdr->host_event_list_entry.next = NULL;
143 }
144 if (event->cpu_event) {
145 dev_dbg(dxgglobaldev, "signal cpu event\n");
146 eventfd_signal(event->cpu_event, 1);
147 if (event->destroy_after_signal)
148 eventfd_ctx_put(event->cpu_event);
149 } else {
150 dev_dbg(dxgglobaldev, "signal completion\n");
151 complete(event->completion_event);
152 }
153 if (event->destroy_after_signal) {
154 dev_dbg(dxgglobaldev, "destroying event %p\n",
155 event);
156 vfree(event);
157 }
158 }
159
160 void dxgglobal_signal_host_event(u64 event_id)
161 {
162 struct dxghostevent *event;
163 unsigned long flags;
164
165 dev_dbg(dxgglobaldev, "%s %lld\n", __func__, event_id);
166
167 spin_lock_irqsave(&dxgglobal->host_event_list_mutex, flags);
168 list_for_each_entry(event, &dxgglobal->host_event_list_head,
169 host_event_list_entry) {
170 if (event->event_id == event_id) {
171 dev_dbg(dxgglobaldev, "found event to signal %lld\n",
172 event_id);
173 if (event->event_type == dxghostevent_cpu_event)
174 signal_host_cpu_event(event);
175 else
176 pr_err("Unknown host event type");
177 break;
178 }
179 }
180 spin_unlock_irqrestore(&dxgglobal->host_event_list_mutex, flags);
181 dev_dbg(dxgglobaldev, "dxgglobal_signal_host_event_end %lld\n",
182 event_id);
183 }
184
185 struct dxghostevent *dxgglobal_get_host_event(u64 event_id)
186 {
187 struct dxghostevent *entry;
188 struct dxghostevent *event = NULL;
189
190 spin_lock_irq(&dxgglobal->host_event_list_mutex);
191 list_for_each_entry(entry, &dxgglobal->host_event_list_head,
192 host_event_list_entry) {
193 if (entry->event_id == event_id) {
194 list_del(&entry->host_event_list_entry);
195 entry->host_event_list_entry.next = NULL;
196 event = entry;
197 break;
198 }
199 }
200 spin_unlock_irq(&dxgglobal->host_event_list_mutex);
201 return event;
202 }
203
204 u64 dxgglobal_new_host_event_id(void)
205 {
206 return atomic64_inc_return(&dxgglobal->host_event_id);
207 }
208
209 void dxgglobal_acquire_process_adapter_lock(void)
210 {
211 mutex_lock(&dxgglobal->process_adapter_mutex);
212 }
213
214 void dxgglobal_release_process_adapter_lock(void)
215 {
216 mutex_unlock(&dxgglobal->process_adapter_mutex);
217 }
218
> 219 int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
220 struct winluid host_vgpu_luid)
221 {
222 struct dxgadapter *adapter;
223 int ret = 0;
224
225 adapter = vzalloc(sizeof(struct dxgadapter));
226 if (adapter == NULL) {
227 ret = -ENOMEM;
228 goto cleanup;
229 }
230
231 adapter->adapter_state = DXGADAPTER_STATE_WAITING_VMBUS;
232 adapter->host_vgpu_luid = host_vgpu_luid;
233 kref_init(&adapter->adapter_kref);
234 init_rwsem(&adapter->core_lock);
235
236 INIT_LIST_HEAD(&adapter->adapter_process_list_head);
237 INIT_LIST_HEAD(&adapter->shared_resource_list_head);
238 INIT_LIST_HEAD(&adapter->adapter_shared_syncobj_list_head);
239 INIT_LIST_HEAD(&adapter->syncobj_list_head);
240 init_rwsem(&adapter->shared_resource_list_lock);
241 adapter->pci_dev = dev;
242 guid_to_luid(guid, &adapter->luid);
243
244 dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL);
245
246 list_add_tail(&adapter->adapter_list_entry,
247 &dxgglobal->adapter_list_head);
248 dxgglobal->num_adapters++;
249 dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL);
250
251 dev_dbg(dxgglobaldev, "new adapter added %p %x-%x\n", adapter,
252 adapter->luid.a, adapter->luid.b);
253 cleanup:
254 dev_dbg(dxgglobaldev, "%s end: %d", __func__, ret);
255 return ret;
256 }
257
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
[not found] ` <1b26482b50832b95a9d8532c493cee6c97323b87.1641937419.git.iourit@linux.microsoft.com>
2022-01-13 1:49 ` [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter kernel test robot
@ 2022-01-13 6:42 ` kernel test robot
2022-01-13 7:43 ` Greg KH
2022-01-13 7:46 ` Greg KH
3 siblings, 0 replies; 33+ messages in thread
From: kernel test robot @ 2022-01-13 6:42 UTC (permalink / raw)
To: Iouri Tarassov, kys, haiyangz, sthemmin, wei.liu, linux-hyperv
Cc: llvm, kbuild-all, linux-kernel, spronovo, gregkh
Hi Iouri,
I love your patch! Perhaps something to improve:
[auto build test WARNING on linus/master]
[also build test WARNING on v5.16 next-20220113]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git e3084ed48fd6b661fe434da0cb36d7d6706cf27f
config: arm64-randconfig-r032-20220113 (https://download.01.org/0day-ci/archive/20220113/202201131405.tgtilUdq-lkp@intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project d1021978b8e7e35dcc30201ca1731d64b5a602a8)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm64 cross compiling tool for clang build
# apt-get install binutils-aarch64-linux-gnu
# https://github.com/0day-ci/linux/commit/00f97c12e2cf0ba4ba1108e2fce9a3d0e287cc8c
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Iouri-Tarassov/drivers-hv-dxgkrnl-Driver-overview/20220113-035836
git checkout 00f97c12e2cf0ba4ba1108e2fce9a3d0e287cc8c
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/hv/dxgkrnl/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> drivers/hv/dxgkrnl/dxgmodule.c:79:20: warning: no previous prototype for function 'find_pci_adapter' [-Wmissing-prototypes]
struct dxgadapter *find_pci_adapter(struct pci_dev *dev)
^
drivers/hv/dxgkrnl/dxgmodule.c:79:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
struct dxgadapter *find_pci_adapter(struct pci_dev *dev)
^
static
>> drivers/hv/dxgkrnl/dxgmodule.c:135:6: warning: no previous prototype for function 'signal_host_cpu_event' [-Wmissing-prototypes]
void signal_host_cpu_event(struct dxghostevent *eventhdr)
^
drivers/hv/dxgkrnl/dxgmodule.c:135:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void signal_host_cpu_event(struct dxghostevent *eventhdr)
^
static
>> drivers/hv/dxgkrnl/dxgmodule.c:219:5: warning: no previous prototype for function 'dxgglobal_create_adapter' [-Wmissing-prototypes]
int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
^
drivers/hv/dxgkrnl/dxgmodule.c:219:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
^
static
3 warnings generated.
--
In file included from drivers/hv/dxgkrnl/dxgvmbus.c:22:
drivers/hv/dxgkrnl/dxgvmbus.h:867:26: warning: implicit conversion from enumeration type 'enum dxgkvmb_commandtype' to different enumeration type 'enum dxgkvmb_commandtype_global' [-Wenum-conversion]
command->command_type = DXGK_VMBCOMMAND_INVALID;
~ ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/hv/dxgkrnl/dxgvmbus.c:116:5: warning: no previous prototype for function 'ntstatus2int' [-Wmissing-prototypes]
int ntstatus2int(struct ntstatus status)
^
drivers/hv/dxgkrnl/dxgvmbus.c:116:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int ntstatus2int(struct ntstatus status)
^
static
>> drivers/hv/dxgkrnl/dxgvmbus.c:219:6: warning: no previous prototype for function 'process_inband_packet' [-Wmissing-prototypes]
void process_inband_packet(struct dxgvmbuschannel *channel,
^
drivers/hv/dxgkrnl/dxgvmbus.c:219:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void process_inband_packet(struct dxgvmbuschannel *channel,
^
static
>> drivers/hv/dxgkrnl/dxgvmbus.c:237:6: warning: no previous prototype for function 'process_completion_packet' [-Wmissing-prototypes]
void process_completion_packet(struct dxgvmbuschannel *channel,
^
drivers/hv/dxgkrnl/dxgvmbus.c:237:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void process_completion_packet(struct dxgvmbuschannel *channel,
^
static
>> drivers/hv/dxgkrnl/dxgvmbus.c:363:5: warning: no previous prototype for function 'dxgvmb_send_async_msg' [-Wmissing-prototypes]
int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
^
drivers/hv/dxgkrnl/dxgvmbus.c:363:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
^
static
drivers/hv/dxgkrnl/dxgvmbus.c:199:20: warning: unused function 'command_vm_to_host_init0' [-Wunused-function]
static inline void command_vm_to_host_init0(struct dxgkvmb_command_vm_to_host
^
6 warnings generated.
vim +/find_pci_adapter +79 drivers/hv/dxgkrnl/dxgmodule.c
78
> 79 struct dxgadapter *find_pci_adapter(struct pci_dev *dev)
80 {
81 struct dxgadapter *entry;
82 struct dxgadapter *adapter = NULL;
83
84 dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL);
85
86 list_for_each_entry(entry, &dxgglobal->adapter_list_head,
87 adapter_list_entry) {
88 if (dev == entry->pci_dev) {
89 adapter = entry;
90 break;
91 }
92 }
93
94 dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL);
95 return adapter;
96 }
97
98 static struct dxgadapter *find_adapter(struct winluid *luid)
99 {
100 struct dxgadapter *entry;
101 struct dxgadapter *adapter = NULL;
102
103 dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL);
104
105 list_for_each_entry(entry, &dxgglobal->adapter_list_head,
106 adapter_list_entry) {
107 if (memcmp(luid, &entry->luid, sizeof(struct winluid)) == 0) {
108 adapter = entry;
109 break;
110 }
111 }
112
113 dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL);
114 return adapter;
115 }
116
117 void dxgglobal_add_host_event(struct dxghostevent *event)
118 {
119 spin_lock_irq(&dxgglobal->host_event_list_mutex);
120 list_add_tail(&event->host_event_list_entry,
121 &dxgglobal->host_event_list_head);
122 spin_unlock_irq(&dxgglobal->host_event_list_mutex);
123 }
124
125 void dxgglobal_remove_host_event(struct dxghostevent *event)
126 {
127 spin_lock_irq(&dxgglobal->host_event_list_mutex);
128 if (event->host_event_list_entry.next != NULL) {
129 list_del(&event->host_event_list_entry);
130 event->host_event_list_entry.next = NULL;
131 }
132 spin_unlock_irq(&dxgglobal->host_event_list_mutex);
133 }
134
> 135 void signal_host_cpu_event(struct dxghostevent *eventhdr)
136 {
137 struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
138
139 if (event->remove_from_list ||
140 event->destroy_after_signal) {
141 list_del(&eventhdr->host_event_list_entry);
142 eventhdr->host_event_list_entry.next = NULL;
143 }
144 if (event->cpu_event) {
145 dev_dbg(dxgglobaldev, "signal cpu event\n");
146 eventfd_signal(event->cpu_event, 1);
147 if (event->destroy_after_signal)
148 eventfd_ctx_put(event->cpu_event);
149 } else {
150 dev_dbg(dxgglobaldev, "signal completion\n");
151 complete(event->completion_event);
152 }
153 if (event->destroy_after_signal) {
154 dev_dbg(dxgglobaldev, "destroying event %p\n",
155 event);
156 vfree(event);
157 }
158 }
159
160 void dxgglobal_signal_host_event(u64 event_id)
161 {
162 struct dxghostevent *event;
163 unsigned long flags;
164
165 dev_dbg(dxgglobaldev, "%s %lld\n", __func__, event_id);
166
167 spin_lock_irqsave(&dxgglobal->host_event_list_mutex, flags);
168 list_for_each_entry(event, &dxgglobal->host_event_list_head,
169 host_event_list_entry) {
170 if (event->event_id == event_id) {
171 dev_dbg(dxgglobaldev, "found event to signal %lld\n",
172 event_id);
173 if (event->event_type == dxghostevent_cpu_event)
174 signal_host_cpu_event(event);
175 else
176 pr_err("Unknown host event type");
177 break;
178 }
179 }
180 spin_unlock_irqrestore(&dxgglobal->host_event_list_mutex, flags);
181 dev_dbg(dxgglobaldev, "dxgglobal_signal_host_event_end %lld\n",
182 event_id);
183 }
184
185 struct dxghostevent *dxgglobal_get_host_event(u64 event_id)
186 {
187 struct dxghostevent *entry;
188 struct dxghostevent *event = NULL;
189
190 spin_lock_irq(&dxgglobal->host_event_list_mutex);
191 list_for_each_entry(entry, &dxgglobal->host_event_list_head,
192 host_event_list_entry) {
193 if (entry->event_id == event_id) {
194 list_del(&entry->host_event_list_entry);
195 entry->host_event_list_entry.next = NULL;
196 event = entry;
197 break;
198 }
199 }
200 spin_unlock_irq(&dxgglobal->host_event_list_mutex);
201 return event;
202 }
203
204 u64 dxgglobal_new_host_event_id(void)
205 {
206 return atomic64_inc_return(&dxgglobal->host_event_id);
207 }
208
209 void dxgglobal_acquire_process_adapter_lock(void)
210 {
211 mutex_lock(&dxgglobal->process_adapter_mutex);
212 }
213
214 void dxgglobal_release_process_adapter_lock(void)
215 {
216 mutex_unlock(&dxgglobal->process_adapter_mutex);
217 }
218
> 219 int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
220 struct winluid host_vgpu_luid)
221 {
222 struct dxgadapter *adapter;
223 int ret = 0;
224
225 adapter = vzalloc(sizeof(struct dxgadapter));
226 if (adapter == NULL) {
227 ret = -ENOMEM;
228 goto cleanup;
229 }
230
231 adapter->adapter_state = DXGADAPTER_STATE_WAITING_VMBUS;
232 adapter->host_vgpu_luid = host_vgpu_luid;
233 kref_init(&adapter->adapter_kref);
234 init_rwsem(&adapter->core_lock);
235
236 INIT_LIST_HEAD(&adapter->adapter_process_list_head);
237 INIT_LIST_HEAD(&adapter->shared_resource_list_head);
238 INIT_LIST_HEAD(&adapter->adapter_shared_syncobj_list_head);
239 INIT_LIST_HEAD(&adapter->syncobj_list_head);
240 init_rwsem(&adapter->shared_resource_list_lock);
241 adapter->pci_dev = dev;
242 guid_to_luid(guid, &adapter->luid);
243
244 dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL);
245
246 list_add_tail(&adapter->adapter_list_entry,
247 &dxgglobal->adapter_list_head);
248 dxgglobal->num_adapters++;
249 dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL);
250
251 dev_dbg(dxgglobaldev, "new adapter added %p %x-%x\n", adapter,
252 adapter->luid.a, adapter->luid.b);
253 cleanup:
254 dev_dbg(dxgglobaldev, "%s end: %d", __func__, ret);
255 return ret;
256 }
257
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
[not found] ` <1b26482b50832b95a9d8532c493cee6c97323b87.1641937419.git.iourit@linux.microsoft.com>
2022-01-13 1:49 ` [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter kernel test robot
2022-01-13 6:42 ` kernel test robot
@ 2022-01-13 7:43 ` Greg KH
2022-01-13 7:46 ` Greg KH
3 siblings, 0 replies; 33+ messages in thread
From: Greg KH @ 2022-01-13 7:43 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On Wed, Jan 12, 2022 at 11:55:06AM -0800, Iouri Tarassov wrote:
> - Add support for a Hyper-V based vGPU implementation that exposes the
> DirectX API to Linux userspace.
> - Handle driver loading, registration for the PCI and VM bus device
> notifications
> - Add headers for user mode interfaces, internal driver objects and VM bus
> communication interface
> - Handle initialization of VM bus channels and creation of the dxgadapter
> object
> - Removed dxg_copy_from_user and dxg_copy_to_user
> - Connect the dxgkrnl module to the drivers/hv/ makefile and Kconfig.
> - Create a MAINTAINERS entry
This looks like a history list?
What exactly is this?
>
> PCI driver registration
>
> A PCI device is created for each virtual GPU (vGPU) device, projected by
> the host. The device vendor is PCI_VENDOR_ID_MICROSOFT and device id is
> PCI_DEVICE_ID_VIRTUAL_RENDER. dxg_pci_probe_device handles arrival of such
> devices and it creates dxgadapter objects. The PCI config space of the
> vGPU device has luid of the corresponding per GPU VM bus channel. This is
> how the adapters are linked to VM bus channels.
>
> dxgadapter initialization
>
> A dxgadapter object represents a virtual GPU, projected to the VM by the
> host. This object can start functioning only when the global VM bus
> channel and the corresponding per vGPU VM bus channel are initialized in
> the guest. Notifications about arrival of vGPU PCI device and VM bus
> channels can happen in any order. Therefore, the initial dxgadapter object
> state is DXGADAPTER_STATE_WAITING_VMBUS. A list of VM bus channels and a
> list of dxgadapter objects are created. When dxgkrnl is notified about a
> VM bus channel arrival, if tries to start all adapters, which are not
> started yet.
>
> VM bus interface version is exchanged by reading/writing the PCI config
> space of the vGPU device.
>
> Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
> ---
> MAINTAINERS | 7 +
> drivers/hv/Kconfig | 2 +
> drivers/hv/Makefile | 1 +
> drivers/hv/dxgkrnl/Kconfig | 26 +
> drivers/hv/dxgkrnl/Makefile | 5 +
> drivers/hv/dxgkrnl/dxgadapter.c | 189 +++
> drivers/hv/dxgkrnl/dxgkrnl.h | 953 +++++++++++++++
> drivers/hv/dxgkrnl/dxgmodule.c | 882 ++++++++++++++
> drivers/hv/dxgkrnl/dxgprocess.c | 37 +
> drivers/hv/dxgkrnl/dxgvmbus.c | 543 +++++++++
> drivers/hv/dxgkrnl/dxgvmbus.h | 901 ++++++++++++++
> drivers/hv/dxgkrnl/hmgr.c | 88 ++
> drivers/hv/dxgkrnl/hmgr.h | 112 ++
> drivers/hv/dxgkrnl/ioctl.c | 37 +
> drivers/hv/dxgkrnl/misc.c | 37 +
> drivers/hv/dxgkrnl/misc.h | 96 ++
> include/linux/hyperv.h | 16 +
> include/uapi/misc/d3dkmthk.h | 1954 +++++++++++++++++++++++++++++++
Why are you adding apis and structures that you are not actually using
in this commit? Please only add the ones that you use, when you use
them.
This commit should be much smaller, and in more different parts.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
[not found] ` <1b26482b50832b95a9d8532c493cee6c97323b87.1641937419.git.iourit@linux.microsoft.com>
` (2 preceding siblings ...)
2022-01-13 7:43 ` Greg KH
@ 2022-01-13 7:46 ` Greg KH
2022-01-14 0:08 ` Iouri Tarassov
3 siblings, 1 reply; 33+ messages in thread
From: Greg KH @ 2022-01-13 7:46 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On Wed, Jan 12, 2022 at 11:55:06AM -0800, Iouri Tarassov wrote:
> + dev_dbg(dxgglobaldev, "%s: %x:%x %p %pUb\n",
> + __func__, adapter->luid.b, adapter->luid.a, hdev->channel,
> + &hdev->channel->offermsg.offer.if_instance);
When I see something like "global device pointer", that is a HUGE red
flag.
No driver should ever have anything that is static to the driver like
this, it should always be per-device. Please use the correct device
model here, which does not include a global pointer, but rather unique
ones that are given to you by the driver core. That way you are never
tied to only "one device per system" as that is a constraint that you
will have to fix eventually, might as well do it all correctly the first
time as it is not any extra effort to do so.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
2022-01-13 7:46 ` Greg KH
@ 2022-01-14 0:08 ` Iouri Tarassov
2022-01-14 5:40 ` Greg KH
0 siblings, 1 reply; 33+ messages in thread
From: Iouri Tarassov @ 2022-01-14 0:08 UTC (permalink / raw)
To: Greg KH
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On 1/12/2022 11:46 PM, Greg KH wrote:
> On Wed, Jan 12, 2022 at 11:55:06AM -0800, Iouri Tarassov wrote:
> > + dev_dbg(dxgglobaldev, "%s: %x:%x %p %pUb\n",
> > + __func__, adapter->luid.b, adapter->luid.a, hdev->channel,
> > + &hdev->channel->offermsg.offer.if_instance);
>
> When I see something like "global device pointer", that is a HUGE red
> flag.
>
> No driver should ever have anything that is static to the driver like
> this, it should always be per-device. Please use the correct device
> model here, which does not include a global pointer, but rather unique
> ones that are given to you by the driver core. That way you are never
> tied to only "one device per system" as that is a constraint that you
> will have to fix eventually, might as well do it all correctly the first
> time as it is not any extra effort to do so
Hi Greg,
dxgglobaldev is a pointer to the global driver data. By design there is a
single hyper-v VM bus and a single corresponding /dev/dxg device.
Virtual GPU adapters are present on the VM bus. /dev/dxg device is used
to enumerate all virtual GPUs, which are accessible only via IOCTLs
to /dev/dxg. dxgglobaldev has a list of all vGPU adapters and
other global driver state. This follows the design on Windows where a single
global object in dxgkrnl.sys driver is used to enumerate and access all
GPU devices. This is also how the public D3DKMT interface to dxgkrnl is
structured.
Thanks
Iouri
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v1 1/9] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
2022-01-14 0:08 ` Iouri Tarassov
@ 2022-01-14 5:40 ` Greg KH
0 siblings, 0 replies; 33+ messages in thread
From: Greg KH @ 2022-01-14 5:40 UTC (permalink / raw)
To: Iouri Tarassov
Cc: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
spronovo
On Thu, Jan 13, 2022 at 04:08:07PM -0800, Iouri Tarassov wrote:
>
> On 1/12/2022 11:46 PM, Greg KH wrote:
> > On Wed, Jan 12, 2022 at 11:55:06AM -0800, Iouri Tarassov wrote:
> > > + dev_dbg(dxgglobaldev, "%s: %x:%x %p %pUb\n",
> > > + __func__, adapter->luid.b, adapter->luid.a, hdev->channel,
> > > + &hdev->channel->offermsg.offer.if_instance);
> >
> > When I see something like "global device pointer", that is a HUGE red
> > flag.
> >
> > No driver should ever have anything that is static to the driver like
> > this, it should always be per-device. Please use the correct device
> > model here, which does not include a global pointer, but rather unique
> > ones that are given to you by the driver core. That way you are never
> > tied to only "one device per system" as that is a constraint that you
> > will have to fix eventually, might as well do it all correctly the first
> > time as it is not any extra effort to do so
> Hi Greg,
>
> dxgglobaldev is a pointer to the global driver data. By design there is a
> single hyper-v VM bus and a single corresponding /dev/dxg device.
That's fine, but use the pointer that you create based on your bus
device, not some static pointer please.
> Virtual GPU adapters are present on the VM bus. /dev/dxg device is used
> to enumerate all virtual GPUs, which are accessible only via IOCTLs
> to /dev/dxg. dxgglobaldev has a list of all vGPU adapters and
> other global driver state. This follows the design on Windows where a single
> global object in dxgkrnl.sys driver is used to enumerate and access all
> GPU devices. This is also how the public D3DKMT interface to dxgkrnl is
> structured.
First off, remember this isn't Windows, let's not make the same mistakes
they have made there please :)
Secondly, this isn't the problem, the issue is that you have a
non-dynamic device here, which is not how Linux drivers should ever
work. It's fine to have a "mux" device like this, but create it
properly, based on the device that the driver core gives you as you must
respect that lifetime, not the lifetime of a static pointer embedded in
a module.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 33+ messages in thread