From: Iouri Tarassov <[email protected]>

Implement ioctls to query statistics from the VGPU device
(LX_DXQUERYSTATISTICS) and to query clock calibration
(LX_DXQUERYCLOCKCALIBRATION).

The LX_DXQUERYSTATISTICS ioctl is used to query various statistics from
the compute device on the host.

The LX_DXQUERYCLOCKCALIBRATION ioctl queries the compute device clock
and is used for performance monitoring.

Signed-off-by: Iouri Tarassov <[email protected]>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <[email protected]>
---
 drivers/hv/dxgkrnl/dxgkrnl.h  |   8 +++
 drivers/hv/dxgkrnl/dxgvmbus.c |  77 +++++++++++++++++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h |  21 +++++++
 drivers/hv/dxgkrnl/ioctl.c    | 111 +++++++++++++++++++++++++++++++++-
 include/uapi/misc/d3dkmthk.h  |  62 +++++++++++++++++++
 5 files changed, 277 insertions(+), 2 deletions(-)

diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index b454c7430f06..a55873bdd9a6 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -885,6 +885,11 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess 
*process,
 int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process,
                                       struct dxgadapter *adapter,
                                       struct d3dkmt_submitcommandtohwqueue *a);
+int dxgvmb_send_query_clock_calibration(struct dxgprocess *process,
+                                       struct dxgadapter *adapter,
+                                       struct d3dkmt_queryclockcalibration *a,
+                                       struct d3dkmt_queryclockcalibration
+                                       *__user inargs);
 int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process,
                                       struct dxgadapter *adapter,
                                       struct d3dkmt_flushheaptransitions *arg);
@@ -929,6 +934,9 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
                                  void *prive_alloc_data,
                                  u32 *res_priv_data_size,
                                  void *priv_res_data);
+int dxgvmb_send_query_statistics(struct dxgprocess *process,
+                                struct dxgadapter *adapter,
+                                struct d3dkmt_querystatistics *args);
 int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
                          void *command,
                          u32 cmd_size);
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index f7264b12a477..9a1864bb4e14 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1829,6 +1829,48 @@ 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)
+               DXG_TRACE("err: %d", ret);
+       return ret;
+}
+
 int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process,
                                       struct dxgadapter *adapter,
                                       struct d3dkmt_flushheaptransitions *args)
@@ -3242,3 +3284,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)
+               DXG_TRACE("err: %d", ret);
+       return ret;
+}
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index a66e11097bb2..17768ed0e68d 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -372,6 +372,16 @@ struct dxgkvmb_command_flushheaptransitions {
        struct dxgkvmb_command_vgpu_to_host hdr;
 };
 
+struct dxgkvmb_command_queryclockcalibration {
+       struct dxgkvmb_command_vgpu_to_host hdr;
+       struct d3dkmt_queryclockcalibration args;
+};
+
+struct dxgkvmb_command_queryclockcalibration_return {
+       struct ntstatus                 status;
+       struct dxgk_gpuclockdata        clock_data;
+};
+
 struct dxgkvmb_command_createallocation_allocinfo {
        u32                             flags;
        u32                             priv_drv_data_size;
@@ -408,6 +418,17 @@ struct dxgkvmb_command_openresource_return {
 /* struct d3dkmthandle   allocation[allocation_count]; */
 };
 
+struct dxgkvmb_command_querystatistics {
+       struct dxgkvmb_command_vgpu_to_host     hdr;
+       struct d3dkmt_querystatistics           args;
+};
+
+struct dxgkvmb_command_querystatistics_return {
+       struct ntstatus                         status;
+       u32                                     reserved;
+       struct d3dkmt_querystatistics_result    result;
+};
+
 struct dxgkvmb_command_getstandardallocprivdata {
        struct dxgkvmb_command_vgpu_to_host hdr;
        enum d3dkmdt_standardallocationtype alloc_type;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index ce4af610ada7..4babb21f38a9 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -149,6 +149,65 @@ static int dxgkio_open_adapter_from_luid(struct dxgprocess 
*process,
        return ret;
 }
 
+static int dxgkio_query_statistics(struct dxgprocess *process,
+                               void __user *inargs)
+{
+       struct d3dkmt_querystatistics *args;
+       int ret;
+       struct dxgadapter *entry;
+       struct dxgadapter *adapter = NULL;
+       struct winluid tmp;
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       args = vzalloc(sizeof(struct d3dkmt_querystatistics));
+       if (args == NULL) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
+       ret = copy_from_user(args, inargs, sizeof(*args));
+       if (ret) {
+               DXG_ERR("failed to copy input args");
+               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) {
+                               DXG_ERR("failed to copy args");
+                               ret = -EINVAL;
+                       }
+               }
+               dxgadapter_release_lock_shared(adapter);
+       }
+
+cleanup:
+       if (args)
+               vfree(args);
+
+       DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+       return ret;
+}
+
 static int
 dxgkp_enum_adapters(struct dxgprocess *process,
                    union d3dkmt_enumadapters_filter filter,
@@ -3536,6 +3595,54 @@ dxgkio_change_vidmem_reservation(struct dxgprocess 
*process, void *__user inargs
        return ret;
 }
 
+static int
+dxgkio_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) {
+               DXG_ERR("failed to copy input args");
+               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) {
+               DXG_ERR("failed to copy output args");
+               ret = -EINVAL;
+       }
+
+cleanup:
+
+       if (adapter_locked)
+               dxgadapter_release_lock_shared(adapter);
+       if (adapter)
+               kref_put(&adapter->adapter_kref, dxgadapter_release);
+       return ret;
+}
+
 static int
 dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user inargs)
 {
@@ -4470,14 +4577,14 @@ static struct ioctl_desc ioctls[] = {
 /* 0x3b */     {dxgkio_wait_sync_object_gpu,
                 LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU},
 /* 0x3c */     {dxgkio_get_allocation_priority, LX_DXGETALLOCATIONPRIORITY},
-/* 0x3d */     {},
+/* 0x3d */     {dxgkio_query_clock_calibration, LX_DXQUERYCLOCKCALIBRATION},
 /* 0x3e */     {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3},
 /* 0x3f */     {dxgkio_share_objects, LX_DXSHAREOBJECTS},
 /* 0x40 */     {dxgkio_open_sync_object_nt, LX_DXOPENSYNCOBJECTFROMNTHANDLE2},
 /* 0x41 */     {dxgkio_query_resource_info_nt,
                 LX_DXQUERYRESOURCEINFOFROMNTHANDLE},
 /* 0x42 */     {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE},
-/* 0x43 */     {},
+/* 0x43 */     {dxgkio_query_statistics, LX_DXQUERYSTATISTICS},
 /* 0x44 */     {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST},
 /* 0x45 */     {},
 };
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index ce5a638a886d..ea18242ceb83 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -996,6 +996,34 @@ struct d3dkmt_queryadapterinfo {
        __u32                           private_data_size;
 };
 
+#pragma pack(push, 1)
+
+struct dxgk_gpuclockdata_flags {
+       union {
+               struct {
+                       __u32   context_management_processor:1;
+                       __u32   reserved:31;
+               };
+               __u32           value;
+       };
+};
+
+struct dxgk_gpuclockdata {
+       __u64                           gpu_frequency;
+       __u64                           gpu_clock_counter;
+       __u64                           cpu_clock_counter;
+       struct dxgk_gpuclockdata_flags  flags;
+} __packed;
+
+struct d3dkmt_queryclockcalibration {
+       struct d3dkmthandle     adapter;
+       __u32                   node_ordinal;
+       __u32                   physical_adapter_index;
+       struct dxgk_gpuclockdata clock_data;
+};
+
+#pragma pack(pop)
+
 struct d3dkmt_flushheaptransitions {
        struct d3dkmthandle     adapter;
 };
@@ -1238,6 +1266,36 @@ struct d3dkmt_enumadapters3 {
 #endif
 };
 
+enum d3dkmt_querystatistics_type {
+       _D3DKMT_QUERYSTATISTICS_ADAPTER                = 0,
+       _D3DKMT_QUERYSTATISTICS_PROCESS                = 1,
+       _D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER        = 2,
+       _D3DKMT_QUERYSTATISTICS_SEGMENT                = 3,
+       _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT        = 4,
+       _D3DKMT_QUERYSTATISTICS_NODE                   = 5,
+       _D3DKMT_QUERYSTATISTICS_PROCESS_NODE           = 6,
+       _D3DKMT_QUERYSTATISTICS_VIDPNSOURCE            = 7,
+       _D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE    = 8,
+       _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP  = 9,
+       _D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER       = 10,
+};
+
+struct d3dkmt_querystatistics_result {
+       char size[0x308];
+};
+
+struct d3dkmt_querystatistics {
+       union {
+               struct {
+                       enum d3dkmt_querystatistics_type        type;
+                       struct winluid                          adapter_luid;
+                       __u64                                   process;
+                       struct d3dkmt_querystatistics_result    result;
+               };
+               char size[0x328];
+       };
+};
+
 struct d3dkmt_shareobjectwithhost {
        struct d3dkmthandle     device_handle;
        struct d3dkmthandle     object_handle;
@@ -1328,6 +1386,8 @@ struct d3dkmt_shareobjectwithhost {
        _IOWR(0x47, 0x3b, struct d3dkmt_waitforsynchronizationobjectfromgpu)
 #define LX_DXGETALLOCATIONPRIORITY     \
        _IOWR(0x47, 0x3c, struct d3dkmt_getallocationpriority)
+#define LX_DXQUERYCLOCKCALIBRATION     \
+       _IOWR(0x47, 0x3d, struct d3dkmt_queryclockcalibration)
 #define LX_DXENUMADAPTERS3             \
        _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3)
 #define LX_DXSHAREOBJECTS              \
@@ -1338,6 +1398,8 @@ struct d3dkmt_shareobjectwithhost {
        _IOWR(0x47, 0x41, struct d3dkmt_queryresourceinfofromnthandle)
 #define LX_DXOPENRESOURCEFROMNTHANDLE  \
        _IOWR(0x47, 0x42, struct d3dkmt_openresourcefromnthandle)
+#define LX_DXQUERYSTATISTICS   \
+       _IOWR(0x47, 0x43, struct d3dkmt_querystatistics)
 #define LX_DXSHAREOBJECTWITHHOST       \
        _IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost)
 

Reply via email to