mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
555 lines
13 KiB
Diff
555 lines
13 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Iouri Tarassov <iourit@linux.microsoft.com>
|
|
Date: Mon, 21 Mar 2022 19:18:50 -0700
|
|
Subject: drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects
|
|
|
|
Implement ioctls to enumerate dxgadapter objects:
|
|
- The LX_DXENUMADAPTERS2 ioctl
|
|
- The LX_DXENUMADAPTERS3 ioctl.
|
|
|
|
Implement ioctls to open adapter by LUID and to close adapter
|
|
handle:
|
|
- The LX_DXOPENADAPTERFROMLUID ioctl
|
|
- the LX_DXCLOSEADAPTER ioctl
|
|
|
|
Impllement the ioctl to query dxgadapter information:
|
|
- The LX_DXQUERYADAPTERINFO ioctl
|
|
|
|
When a dxgadapter is enumerated, it is implicitely opened and
|
|
a handle (d3dkmthandle) is created in the current process handle
|
|
table. The handle is returned to the caller and can be used
|
|
by user mode to reference the VGPU adapter in other ioctls.
|
|
|
|
The caller is responsible to close the adapter when it is not
|
|
longer used by sending the LX_DXCLOSEADAPTER ioctl.
|
|
|
|
A dxgprocess has a list of opened dxgadapter objects
|
|
(dxgprocess_adapter is used to represent the entry in the list).
|
|
A dxgadapter also has a list of dxgprocess_adapter objects.
|
|
This is needed for cleanup because either a process or an adapter
|
|
could be destroyed first.
|
|
|
|
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
|
|
[kms: Forward port to v6.1]
|
|
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
|
|
---
|
|
drivers/hv/dxgkrnl/dxgmodule.c | 3 +
|
|
drivers/hv/dxgkrnl/ioctl.c | 482 +++++++++-
|
|
2 files changed, 484 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgmodule.c
|
|
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
|
|
@@ -721,6 +721,9 @@ static struct dxgglobal *dxgglobal_create(void)
|
|
|
|
init_rwsem(&dxgglobal->channel_lock);
|
|
|
|
+#ifdef DEBUG
|
|
+ dxgk_validate_ioctls();
|
|
+#endif
|
|
return dxgglobal;
|
|
}
|
|
|
|
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/ioctl.c
|
|
+++ b/drivers/hv/dxgkrnl/ioctl.c
|
|
@@ -29,8 +29,472 @@ struct ioctl_desc {
|
|
u32 arg_size;
|
|
};
|
|
|
|
-static struct ioctl_desc ioctls[] = {
|
|
+#ifdef DEBUG
|
|
+static char *errorstr(int ret)
|
|
+{
|
|
+ return ret < 0 ? "err" : "";
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int dxgkio_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;
|
|
+ struct dxgglobal *dxgglobal = dxggbl();
|
|
+
|
|
+ ret = copy_from_user(&args, inargs, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("Faled to copy input args");
|
|
+ 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) {
|
|
+ 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);
|
|
+
|
|
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), 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;
|
|
+ struct dxgglobal *dxgglobal = dxggbl();
|
|
+
|
|
+ if (info_out == NULL || adapter_count_max == 0) {
|
|
+ ret = copy_to_user(adapter_count_out,
|
|
+ &dxgglobal->num_adapters, sizeof(u32));
|
|
+ if (ret) {
|
|
+ DXG_ERR("copy_to_user faled");
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (adapter_count_max > 0xFFFF) {
|
|
+ DXG_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;
|
|
+ DXG_TRACE("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;
|
|
+ DXG_TRACE("Too many adapters");
|
|
+ ret = copy_to_user(adapter_count_out,
|
|
+ &dxgglobal->num_adapters, sizeof(u32));
|
|
+ if (ret) {
|
|
+ DXG_ERR("copy_to_user failed");
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ ret = copy_to_user(adapter_count_out, &adapter_count,
|
|
+ sizeof(adapter_count));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy adapter_count");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ ret = copy_to_user(info_out, info, sizeof(info[0]) * adapter_count);
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy adapter info");
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+
|
|
+cleanup:
|
|
+
|
|
+ if (ret >= 0) {
|
|
+ DXG_TRACE("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);
|
|
+
|
|
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+dxgkio_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;
|
|
+ struct dxgglobal *dxgglobal = dxggbl();
|
|
+
|
|
+ ret = copy_from_user(&args, inargs, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy input args");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (args.adapters == NULL) {
|
|
+ DXG_TRACE("buffer is NULL");
|
|
+ args.num_adapters = dxgglobal->num_adapters;
|
|
+ ret = copy_to_user(inargs, &args, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy args to user");
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+ goto cleanup;
|
|
+ }
|
|
+ if (args.num_adapters < dxgglobal->num_adapters) {
|
|
+ args.num_adapters = dxgglobal->num_adapters;
|
|
+ DXG_TRACE("buffer is too small");
|
|
+ ret = -EOVERFLOW;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (args.num_adapters > D3DKMT_ADAPTERS_MAX) {
|
|
+ DXG_TRACE("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;
|
|
+ DXG_TRACE("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) {
|
|
+ DXG_ERR("failed to copy args to user");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+ ret = copy_to_user(args.adapters, info,
|
|
+ sizeof(info[0]) * args.num_adapters);
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy adapter info to user");
|
|
+ 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 {
|
|
+ DXG_TRACE("found %d adapters", args.num_adapters);
|
|
+ }
|
|
+
|
|
+ if (info)
|
|
+ vfree(info);
|
|
+ if (adapters)
|
|
+ vfree(adapters);
|
|
+
|
|
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+dxgkio_enum_adapters3(struct dxgprocess *process, void *__user inargs)
|
|
+{
|
|
+ struct d3dkmt_enumadapters3 args;
|
|
+ int ret;
|
|
+
|
|
+ ret = copy_from_user(&args, inargs, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy input args");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ ret = dxgkp_enum_adapters(process, args.filter,
|
|
+ args.adapter_count,
|
|
+ args.adapters,
|
|
+ &((struct d3dkmt_enumadapters3 *)inargs)->
|
|
+ adapter_count);
|
|
+
|
|
+cleanup:
|
|
+
|
|
+ DXG_TRACE("ioctl: %s %d", errorstr(ret), ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+dxgkio_close_adapter(struct dxgprocess *process, void *__user inargs)
|
|
+{
|
|
+ struct d3dkmthandle args;
|
|
+ int ret;
|
|
+
|
|
+ ret = copy_from_user(&args, inargs, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy input args");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ ret = dxgprocess_close_adapter(process, args);
|
|
+ if (ret < 0)
|
|
+ DXG_ERR("failed to close adapter: %d", ret);
|
|
+
|
|
+cleanup:
|
|
+
|
|
+ DXG_TRACE("ioctl: %s %d", errorstr(ret), ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+dxgkio_query_adapter_info(struct dxgprocess *process, void *__user inargs)
|
|
+{
|
|
+ struct d3dkmt_queryadapterinfo args;
|
|
+ int ret;
|
|
+ struct dxgadapter *adapter = NULL;
|
|
+
|
|
+ ret = copy_from_user(&args, inargs, sizeof(args));
|
|
+ if (ret) {
|
|
+ DXG_ERR("failed to copy input args");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (args.private_data_size > DXG_MAX_VM_BUS_PACKET_SIZE ||
|
|
+ args.private_data_size == 0) {
|
|
+ DXG_ERR("invalid private data size");
|
|
+ ret = -EINVAL;
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ DXG_TRACE("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);
|
|
+
|
|
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static struct ioctl_desc ioctls[] = {
|
|
+/* 0x00 */ {},
|
|
+/* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID},
|
|
+/* 0x02 */ {},
|
|
+/* 0x03 */ {},
|
|
+/* 0x04 */ {},
|
|
+/* 0x05 */ {},
|
|
+/* 0x06 */ {},
|
|
+/* 0x07 */ {},
|
|
+/* 0x08 */ {},
|
|
+/* 0x09 */ {dxgkio_query_adapter_info, LX_DXQUERYADAPTERINFO},
|
|
+/* 0x0a */ {},
|
|
+/* 0x0b */ {},
|
|
+/* 0x0c */ {},
|
|
+/* 0x0d */ {},
|
|
+/* 0x0e */ {},
|
|
+/* 0x0f */ {},
|
|
+/* 0x10 */ {},
|
|
+/* 0x11 */ {},
|
|
+/* 0x12 */ {},
|
|
+/* 0x13 */ {},
|
|
+/* 0x14 */ {dxgkio_enum_adapters, LX_DXENUMADAPTERS2},
|
|
+/* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER},
|
|
+/* 0x16 */ {},
|
|
+/* 0x17 */ {},
|
|
+/* 0x18 */ {},
|
|
+/* 0x19 */ {},
|
|
+/* 0x1a */ {},
|
|
+/* 0x1b */ {},
|
|
+/* 0x1c */ {},
|
|
+/* 0x1d */ {},
|
|
+/* 0x1e */ {},
|
|
+/* 0x1f */ {},
|
|
+/* 0x20 */ {},
|
|
+/* 0x21 */ {},
|
|
+/* 0x22 */ {},
|
|
+/* 0x23 */ {},
|
|
+/* 0x24 */ {},
|
|
+/* 0x25 */ {},
|
|
+/* 0x26 */ {},
|
|
+/* 0x27 */ {},
|
|
+/* 0x28 */ {},
|
|
+/* 0x29 */ {},
|
|
+/* 0x2a */ {},
|
|
+/* 0x2b */ {},
|
|
+/* 0x2c */ {},
|
|
+/* 0x2d */ {},
|
|
+/* 0x2e */ {},
|
|
+/* 0x2f */ {},
|
|
+/* 0x30 */ {},
|
|
+/* 0x31 */ {},
|
|
+/* 0x32 */ {},
|
|
+/* 0x33 */ {},
|
|
+/* 0x34 */ {},
|
|
+/* 0x35 */ {},
|
|
+/* 0x36 */ {},
|
|
+/* 0x37 */ {},
|
|
+/* 0x38 */ {},
|
|
+/* 0x39 */ {},
|
|
+/* 0x3a */ {},
|
|
+/* 0x3b */ {},
|
|
+/* 0x3c */ {},
|
|
+/* 0x3d */ {},
|
|
+/* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3},
|
|
+/* 0x3f */ {},
|
|
+/* 0x40 */ {},
|
|
+/* 0x41 */ {},
|
|
+/* 0x42 */ {},
|
|
+/* 0x43 */ {},
|
|
+/* 0x44 */ {},
|
|
+/* 0x45 */ {},
|
|
};
|
|
|
|
/*
|
|
@@ -82,3 +546,19 @@ long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2)
|
|
DXG_TRACE("unlocked ioctl %x Code:%d", p1, _IOC_NR(p1));
|
|
return dxgk_ioctl(f, p1, p2);
|
|
}
|
|
+
|
|
+#ifdef DEBUG
|
|
+void dxgk_validate_ioctls(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i=0; i < ARRAY_SIZE(ioctls); i++)
|
|
+ {
|
|
+ if (ioctls[i].ioctl && _IOC_NR(ioctls[i].ioctl) != i)
|
|
+ {
|
|
+ DXG_ERR("Invalid ioctl");
|
|
+ DXGKRNL_ASSERT(0);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif
|
|
--
|
|
Armbian
|
|
|