* [PATCH 50/55] drivers: hv: dxgkrnl: Fix build breaks when switching to 6.6 kernel due to removed uuid_le_cmp
From: Eric Curtin @ 2026-03-19 20:25 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
uuid_le_cmp was removed and needs to be replaced by guid_equal. The
relevant upstream commits are:
1fb1ea0d9cb8 "mei: Move uuid.h to the MEI namespace"
f5b3c341a46e "mei: Move uuid_le_cmp() to its only user"
5e6a51787fef "uuid: Decouple guid_t and uuid_le types and respective macros"
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgmodule.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index 5459bd9b82fb..e3ac70df1b6f 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -762,7 +762,7 @@ static int dxg_probe_vmbus(struct hv_device *hdev,
mutex_lock(&dxgglobal->device_mutex);
- if (uuid_le_cmp(hdev->dev_type, dxg_vmbus_id_table[0].guid) == 0) {
+ if (guid_equal(&hdev->dev_type, &dxg_vmbus_id_table[0].guid)) {
/* This is a new virtual GPU channel */
guid_to_luid(&hdev->channel->offermsg.offer.if_instance, &luid);
DXG_TRACE("vGPU channel: %pUb",
@@ -777,8 +777,7 @@ static int dxg_probe_vmbus(struct hv_device *hdev,
list_add_tail(&vgpuch->vgpu_ch_list_entry,
&dxgglobal->vgpu_ch_list_head);
dxgglobal_start_adapters();
- } else if (uuid_le_cmp(hdev->dev_type,
- dxg_vmbus_id_table[1].guid) == 0) {
+ } else if (guid_equal(&hdev->dev_type, &dxg_vmbus_id_table[1].guid)) {
/* This is the global Dxgkgnl channel */
DXG_TRACE("Global channel: %pUb",
&hdev->channel->offermsg.offer.if_instance);
@@ -810,7 +809,7 @@ static void dxg_remove_vmbus(struct hv_device *hdev)
mutex_lock(&dxgglobal->device_mutex);
- if (uuid_le_cmp(hdev->dev_type, dxg_vmbus_id_table[0].guid) == 0) {
+ if (guid_equal(&hdev->dev_type, &dxg_vmbus_id_table[0].guid)) {
DXG_TRACE("Remove virtual GPU channel");
dxgglobal_stop_adapter_vmbus(hdev);
list_for_each_entry(vgpu_channel,
@@ -822,8 +821,7 @@ static void dxg_remove_vmbus(struct hv_device *hdev)
break;
}
}
- } else if (uuid_le_cmp(hdev->dev_type,
- dxg_vmbus_id_table[1].guid) == 0) {
+ } else if (guid_equal(&hdev->dev_type, &dxg_vmbus_id_table[1].guid)) {
DXG_TRACE("Remove global channel device");
dxgglobal_destroy_global_channel();
} else {
^ permalink raw reply related
* [PATCH 49/55] drivers: hv: dxgkrnl: Fix build breaks when switching to 6.6 kernel due to hv_driver remove callback change.
From: Eric Curtin @ 2026-03-19 20:25 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
The hv_driver remove callback has been updated to return void instead of int.
dxg_remove_vmbus() in dxgmodule.c needs to be updated to match. See this
commit for more context:
96ec2939620c "Drivers: hv: Make remove callback of hyperv driver void returned"
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
---
drivers/hv/dxgkrnl/dxgmodule.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index 0fafb6167229..5459bd9b82fb 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -803,9 +803,8 @@ static int dxg_probe_vmbus(struct hv_device *hdev,
return ret;
}
-static int dxg_remove_vmbus(struct hv_device *hdev)
+static void dxg_remove_vmbus(struct hv_device *hdev)
{
- int ret = 0;
struct dxgvgpuchannel *vgpu_channel;
struct dxgglobal *dxgglobal = dxggbl();
@@ -830,12 +829,9 @@ static int dxg_remove_vmbus(struct hv_device *hdev)
} else {
/* Unknown device type */
DXG_ERR("Unknown device type");
- ret = -ENODEV;
}
mutex_unlock(&dxgglobal->device_mutex);
-
- return ret;
}
MODULE_DEVICE_TABLE(vmbus, dxg_vmbus_id_table);
^ permalink raw reply related
* [PATCH 48/55] drivers: hv: dxgkrnl: Add support for locking a shared allocation by not the owner
From: Eric Curtin @ 2026-03-19 20:25 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
WDDM has a restriction that an allocation of a shared resource can be
locked for CPU access only by the resource creator (the owner). This
restriction is removed for system memory only allocations. This change
adds support for this feature.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 4 ++--
drivers/hv/dxgkrnl/dxgkrnl.h | 13 ++++++++++++-
drivers/hv/dxgkrnl/ioctl.c | 25 +++++++++++++++++--------
3 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index b8ae8099847b..cf946e476411 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -559,8 +559,8 @@ void dxgsharedresource_destroy(struct kref *refcount)
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_info)
+ vfree(resource->alloc_info);
if (resource->alloc_private_data)
vfree(resource->alloc_private_data);
kfree(resource);
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index a4d0c504668b..d816a875d5ab 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -613,6 +613,17 @@ struct dxghwqueue *dxghwqueue_create(struct dxgcontext *ctx);
void dxghwqueue_destroy(struct dxgprocess *pr, struct dxghwqueue *hq);
void dxghwqueue_release(struct kref *refcount);
+/*
+ * When a shared resource is created this structure provides information
+ * about every allocation in the resource. It is used when someone opens the
+ * resource and locks its allocation.
+ */
+struct dxgsharedallocdata {
+ u32 private_data_size; /* Size of private data */
+ u32 num_pages; /* Allocation size in pages */
+ bool cached; /* True is the alloc memory is cached */
+};
+
/*
* A shared resource object is created to track the list of dxgresource objects,
* which are opened for the same underlying shared resource.
@@ -658,7 +669,7 @@ struct dxgsharedresource {
};
long flags;
};
- u32 *alloc_private_data_sizes;
+ struct dxgsharedallocdata *alloc_info;
u8 *alloc_private_data;
u8 *runtime_private_data;
u8 *resource_private_data;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index d91af2e176e9..f8f116a7f87f 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -369,6 +369,7 @@ static int dxgsharedresource_seal(struct dxgsharedresource *shared_resource)
u32 data_size;
struct dxgresource *resource;
struct dxgallocation *alloc;
+ struct dxgsharedallocdata *alloc_info;
DXG_TRACE("Sealing resource: %p", shared_resource);
@@ -409,9 +410,10 @@ static int dxgsharedresource_seal(struct dxgsharedresource *shared_resource)
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) {
+ shared_resource->alloc_info =
+ vzalloc(sizeof(struct dxgsharedallocdata) *
+ shared_resource->allocation_count);
+ if (shared_resource->alloc_info == NULL) {
ret = -EINVAL;
goto cleanup1;
}
@@ -429,8 +431,10 @@ static int dxgsharedresource_seal(struct dxgsharedresource *shared_resource)
ret = -EINVAL;
goto cleanup1;
}
- shared_resource->alloc_private_data_sizes[i] =
- alloc_data_size;
+ alloc_info = &shared_resource->alloc_info[i];
+ alloc_info->private_data_size = alloc_data_size;
+ alloc_info->num_pages = alloc->num_pages;
+ alloc_info->cached = alloc->cached;
memcpy(private_data,
alloc->priv_drv_data->data,
alloc_data_size);
@@ -5031,6 +5035,7 @@ assign_resource_handles(struct dxgprocess *process,
u8 *cur_priv_data;
u32 total_priv_data_size = 0;
struct d3dddi_openallocationinfo2 open_alloc_info = { };
+ struct dxgsharedallocdata *alloc_info;
hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
ret = hmgrtable_assign_handle(&process->handle_table, resource,
@@ -5050,11 +5055,15 @@ assign_resource_handles(struct dxgprocess *process,
allocs[i]->alloc_handle = handles[i];
allocs[i]->handle_valid = 1;
open_alloc_info.allocation = handles[i];
- if (shared_resource->alloc_private_data_sizes)
+ if (shared_resource->alloc_info) {
+ alloc_info = &shared_resource->alloc_info[i];
open_alloc_info.priv_drv_data_size =
- shared_resource->alloc_private_data_sizes[i];
- else
+ alloc_info->private_data_size;
+ allocs[i]->num_pages = alloc_info->num_pages;
+ allocs[i]->cached = alloc_info->cached;
+ } 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;
^ permalink raw reply related
* [PATCH 47/55] drivers: hv: dxgkrnl: Retry sending a VM bus packet when there is no place in the ring buffer
From: Eric Curtin @ 2026-03-19 20:25 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
When D3DKMT requests are sent too quickly, the VM bus ring buffer could be
full when a message is submitted. The change adds sleep and re-try count
to handle this condition.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgvmbus.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 67f55f4bf41d..467e7707c8c7 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -420,6 +420,7 @@ int dxgvmb_send_sync_msg(struct dxgvmbuschannel *channel,
struct dxgvmbuspacket *packet = NULL;
struct dxgkvmb_command_vm_to_host *cmd1;
struct dxgkvmb_command_vgpu_to_host *cmd2;
+ int try_count = 0;
if (cmd_size > DXG_MAX_VM_BUS_PACKET_SIZE ||
result_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
@@ -453,9 +454,19 @@ int dxgvmb_send_sync_msg(struct dxgvmbuschannel *channel,
list_add_tail(&packet->packet_list_entry, &channel->packet_list_head);
spin_unlock_irq(&channel->packet_list_mutex);
- ret = vmbus_sendpacket(channel->channel, command, cmd_size,
- packet->request_id, VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ do {
+ ret = vmbus_sendpacket(channel->channel, command, cmd_size,
+ packet->request_id, VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ /*
+ * -EAGAIN is returned when the VM bus ring buffer if full.
+ * Wait 2ms to allow the host to process messages and try again.
+ */
+ if (ret == -EAGAIN) {
+ usleep_range(1000, 2000);
+ try_count++;
+ }
+ } while (ret == -EAGAIN && try_count < 50);
if (ret) {
DXG_ERR("vmbus_sendpacket failed: %x", ret);
spin_lock_irq(&channel->packet_list_mutex);
^ permalink raw reply related
* [PATCH 46/55] drivers: hv: dxgkrnl: Fixed the implementation of D3DKMTQueryClockCalibration
From: Eric Curtin @ 2026-03-19 20:25 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
The result of a VM bus call was not copied to the user output structure.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgvmbus.c | 18 ++++++++++--------
drivers/hv/dxgkrnl/ioctl.c | 5 -----
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 215e2f6648e2..67f55f4bf41d 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1966,14 +1966,16 @@ int dxgvmb_send_query_clock_calibration(struct dxgprocess *process,
*__user inargs)
{
struct dxgkvmb_command_queryclockcalibration *command;
- struct dxgkvmb_command_queryclockcalibration_return result;
+ struct dxgkvmb_command_queryclockcalibration_return *result;
int ret;
- struct dxgvmbusmsg msg = {.hdr = NULL};
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
- ret = init_message(&msg, adapter, process, sizeof(*command));
+ ret = init_message_res(&msg, adapter, sizeof(*command),
+ sizeof(*result));
if (ret)
goto cleanup;
command = (void *)msg.msg;
+ result = msg.res;
command_vgpu_to_host_init2(&command->hdr,
DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION,
@@ -1981,20 +1983,20 @@ int dxgvmb_send_query_clock_calibration(struct dxgprocess *process,
command->args = *args;
ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
- &result, sizeof(result));
+ result, sizeof(*result));
if (ret < 0)
goto cleanup;
- ret = copy_to_user(&inargs->clock_data, &result.clock_data,
- sizeof(result.clock_data));
+ ret = copy_to_user(&inargs->clock_data, &result->clock_data,
+ sizeof(result->clock_data));
if (ret) {
DXG_ERR("failed to copy clock data");
ret = -EFAULT;
goto cleanup;
}
- ret = ntstatus2int(result.status);
+ ret = ntstatus2int(result->status);
cleanup:
- free_message(&msg);
+ free_message((struct dxgvmbusmsg *)&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 5ac6dd1f09b9..d91af2e176e9 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -4303,11 +4303,6 @@ dxgkio_query_clock_calibration(struct dxgprocess *process, void *__user inargs)
&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 = -EFAULT;
- }
cleanup:
^ permalink raw reply related
* [PATCH 45/55] drivers: hv: dxgkrnl: Fixed coding style issues
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 12 ++++--------
drivers/hv/dxgkrnl/dxgkrnl.h | 6 +++---
drivers/hv/dxgkrnl/dxgvmbus.c | 2 +-
drivers/hv/dxgkrnl/ioctl.c | 20 +++++++-------------
4 files changed, 15 insertions(+), 25 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index bcd19b7267d1..b8ae8099847b 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -1017,8 +1017,7 @@ struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
}
return adapter_info;
cleanup:
- if (adapter_info)
- kfree(adapter_info);
+ kfree(adapter_info);
return NULL;
}
@@ -1225,10 +1224,8 @@ struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
DXG_TRACE("Syncobj created: %p", syncobj);
return syncobj;
cleanup:
- if (syncobj->host_event)
- kfree(syncobj->host_event);
- if (syncobj)
- kfree(syncobj);
+ kfree(syncobj->host_event);
+ kfree(syncobj);
return NULL;
}
@@ -1308,8 +1305,7 @@ void dxgsyncobject_release(struct kref *refcount)
kref_put(&syncobj->shared_owner->ssyncobj_kref,
dxgsharedsyncobj_release);
}
- if (syncobj->host_event)
- kfree(syncobj->host_event);
+ kfree(syncobj->host_event);
kfree(syncobj);
}
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 9599ec8e0f1d..a4d0c504668b 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -47,10 +47,10 @@ struct dxghwqueue;
* Driver private data.
* A single /dev/dxg device is created per virtual machine.
*/
-struct dxgdriver{
+struct dxgdriver {
struct dxgglobal *dxgglobal;
- struct device *dxgdev;
- struct pci_driver pci_drv;
+ struct device *dxgdev;
+ struct pci_driver pci_drv;
struct hv_driver vmbus_drv;
};
extern struct dxgdriver dxgdrv;
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index de28c6162a70..215e2f6648e2 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -246,7 +246,7 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hdev)
goto cleanup;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0)
+#if KERNEL_VERSION(5, 15, 0) <= LINUX_VERSION_CODE
hdev->channel->max_pkt_size = DXG_MAX_VM_BUS_PACKET_SIZE;
#endif
ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE,
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index f8ca79d098f3..5ac6dd1f09b9 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -3162,8 +3162,7 @@ dxgkio_signal_sync_object(struct dxgprocess *process, void *__user inargs)
}
if (event)
eventfd_ctx_put(event);
- if (host_event)
- kfree(host_event);
+ kfree(host_event);
}
if (adapter)
dxgadapter_release_lock_shared(adapter);
@@ -3398,8 +3397,7 @@ dxgkio_signal_sync_object_gpu2(struct dxgprocess *process, void *__user inargs)
}
if (event)
eventfd_ctx_put(event);
- if (host_event)
- kfree(host_event);
+ kfree(host_event);
}
if (adapter)
dxgadapter_release_lock_shared(adapter);
@@ -3577,8 +3575,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
}
if (event)
eventfd_ctx_put(event);
- if (async_host_event)
- kfree(async_host_event);
+ kfree(async_host_event);
}
DXG_TRACE_IOCTL_END(ret);
@@ -4438,7 +4435,7 @@ build_test_command_buffer(struct dxgprocess *process,
if (cmd.dma_buffer_size < sizeof(u32) ||
cmd.dma_buffer_size > D3DDDI_MAXTESTBUFFERSIZE ||
cmd.dma_buffer_priv_data_size >
- D3DDDI_MAXTESTBUFFERPRIVATEDRIVERDATASIZE) {
+ D3DDDI_MAXTESTBUFFERPRIVATEDRIVERDATASIZE) {
DXG_ERR("Invalid DMA buffer or private data size");
return -EINVAL;
}
@@ -4511,8 +4508,7 @@ driver_known_escape(struct dxgprocess *process,
enum d3dkmt_escapetype escape_type;
int ret = 0;
- if (args->priv_drv_data_size < sizeof(enum d3dddi_knownescapetype))
- {
+ if (args->priv_drv_data_size < sizeof(enum d3dddi_knownescapetype)) {
DXG_ERR("Invalid private data size");
return -EINVAL;
}
@@ -5631,10 +5627,8 @@ 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)
- {
+ 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);
}
^ permalink raw reply related
* [PATCH 44/55] drivers: hv: dxgkrnl: Implement known escapes
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Implement an escape to build test command buffer.
Implement other known escapes.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 3 +-
drivers/hv/dxgkrnl/dxgvmbus.c | 40 +++++---
drivers/hv/dxgkrnl/ioctl.c | 170 +++++++++++++++++++++++++++++-----
include/uapi/misc/d3dkmthk.h | 31 +++++++
4 files changed, 205 insertions(+), 39 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index ebf81cffa289..9599ec8e0f1d 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -953,7 +953,8 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
*args);
int dxgvmb_send_escape(struct dxgprocess *process,
struct dxgadapter *adapter,
- struct d3dkmt_escape *args);
+ struct d3dkmt_escape *args,
+ bool user_mode);
int dxgvmb_send_query_vidmem_info(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_queryvideomemoryinfo *args,
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 2436e1a7bc73..de28c6162a70 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -2174,7 +2174,8 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
int dxgvmb_send_escape(struct dxgprocess *process,
struct dxgadapter *adapter,
- struct d3dkmt_escape *args)
+ struct d3dkmt_escape *args,
+ bool user_mode)
{
int ret;
struct dxgkvmb_command_escape *command = NULL;
@@ -2203,13 +2204,18 @@ int dxgvmb_send_escape(struct dxgprocess *process,
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) {
- DXG_ERR("failed to copy priv data");
- ret = -EFAULT;
- goto cleanup;
+ if (user_mode) {
+ ret = copy_from_user(command->priv_drv_data,
+ args->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ DXG_ERR("failed to copy priv data");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+ } else {
+ memcpy(command->priv_drv_data, args->priv_drv_data,
+ args->priv_drv_data_size);
}
}
@@ -2220,12 +2226,18 @@ int dxgvmb_send_escape(struct dxgprocess *process,
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) {
- DXG_ERR("failed to copy priv data");
- ret = -EINVAL;
+ if (user_mode) {
+ ret = copy_to_user(args->priv_drv_data,
+ command->priv_drv_data,
+ args->priv_drv_data_size);
+ if (ret) {
+ DXG_ERR("failed to copy priv data");
+ ret = -EINVAL;
+ }
+ } else {
+ memcpy(args->priv_drv_data,
+ command->priv_drv_data,
+ args->priv_drv_data_size);
}
}
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 5ff4b27af19d..f8ca79d098f3 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -4257,10 +4257,8 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *process, void *__user inargs
}
ret = dxgadapter_acquire_lock_shared(adapter);
- if (ret < 0) {
- adapter = NULL;
+ if (ret < 0)
goto cleanup;
- }
adapter_locked = true;
args.adapter.v = 0;
ret = dxgvmb_send_change_vidmem_reservation(process, adapter,
@@ -4299,10 +4297,8 @@ dxgkio_query_clock_calibration(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
- if (ret < 0) {
- adapter = NULL;
+ if (ret < 0)
goto cleanup;
- }
adapter_locked = true;
args.adapter = adapter->host_handle;
@@ -4349,10 +4345,8 @@ dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
- if (ret < 0) {
- adapter = NULL;
+ if (ret < 0)
goto cleanup;
- }
adapter_locked = true;
args.adapter = adapter->host_handle;
@@ -4417,6 +4411,134 @@ dxgkio_invalidate_cache(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+build_test_command_buffer(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_escape *args)
+{
+ int ret;
+ struct d3dddi_buildtestcommandbuffer cmd;
+ struct d3dkmt_escape newargs = *args;
+ u32 buf_size;
+ struct d3dddi_buildtestcommandbuffer *buf = NULL;
+ struct d3dddi_buildtestcommandbuffer *__user ucmd;
+
+ ucmd = args->priv_drv_data;
+ if (args->priv_drv_data_size <
+ sizeof(struct d3dddi_buildtestcommandbuffer)) {
+ DXG_ERR("Invalid private data size");
+ return -EINVAL;
+ }
+ ret = copy_from_user(&cmd, ucmd, sizeof(cmd));
+ if (ret) {
+ DXG_ERR("Failed to copy private data");
+ return -EFAULT;
+ }
+
+ if (cmd.dma_buffer_size < sizeof(u32) ||
+ cmd.dma_buffer_size > D3DDDI_MAXTESTBUFFERSIZE ||
+ cmd.dma_buffer_priv_data_size >
+ D3DDDI_MAXTESTBUFFERPRIVATEDRIVERDATASIZE) {
+ DXG_ERR("Invalid DMA buffer or private data size");
+ return -EINVAL;
+ }
+ /* Allocate a new buffer for the escape call */
+ buf_size = sizeof(struct d3dddi_buildtestcommandbuffer) +
+ cmd.dma_buffer_size +
+ cmd.dma_buffer_priv_data_size;
+ buf = vzalloc(buf_size);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ *buf = cmd;
+ buf->dma_buffer = NULL;
+ buf->dma_buffer_priv_data = NULL;
+
+ /* Replace private data in the escape arguments and call the host */
+ newargs.priv_drv_data = buf;
+ newargs.priv_drv_data_size = buf_size;
+ ret = dxgvmb_send_escape(process, adapter, &newargs, false);
+ if (ret) {
+ DXG_ERR("Host failed escape");
+ goto cleanup;
+ }
+
+ ret = copy_to_user(&ucmd->dma_buffer_size, &buf->dma_buffer_size,
+ sizeof(u32));
+ if (ret) {
+ DXG_ERR("Failed to dma size to user");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+ ret = copy_to_user(&ucmd->dma_buffer_priv_data_size,
+ &buf->dma_buffer_priv_data_size,
+ sizeof(u32));
+ if (ret) {
+ DXG_ERR("Failed to dma private data size to user");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+ ret = copy_to_user(cmd.dma_buffer, (char *)buf + sizeof(*buf),
+ buf->dma_buffer_size);
+ if (ret) {
+ DXG_ERR("Failed to copy dma buffer to user");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+ if (buf->dma_buffer_priv_data_size) {
+ ret = copy_to_user(cmd.dma_buffer_priv_data,
+ (char *)buf + sizeof(*buf) + cmd.dma_buffer_size,
+ buf->dma_buffer_priv_data_size);
+ if (ret) {
+ DXG_ERR("Failed to copy private data to user");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (buf)
+ vfree(buf);
+ return ret;
+}
+
+static int
+driver_known_escape(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_escape *args)
+{
+ enum d3dkmt_escapetype escape_type;
+ int ret = 0;
+
+ if (args->priv_drv_data_size < sizeof(enum d3dddi_knownescapetype))
+ {
+ DXG_ERR("Invalid private data size");
+ return -EINVAL;
+ }
+ ret = copy_from_user(&escape_type, args->priv_drv_data,
+ sizeof(escape_type));
+ if (ret) {
+ DXG_ERR("Failed to read escape type");
+ return -EFAULT;
+ }
+ switch (escape_type) {
+ case _D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE:
+ case _D3DDDI_DRIVERESCAPETYPE_TRANSLATERESOURCEHANDLE:
+ /*
+ * The host and VM handles are the same
+ */
+ break;
+ case _D3DDDI_DRIVERESCAPETYPE_BUILDTESTCOMMANDBUFFER:
+ ret = build_test_command_buffer(process, adapter, args);
+ break;
+ default:
+ ret = dxgvmb_send_escape(process, adapter, args, true);
+ break;
+ }
+ return ret;
+}
+
static int
dxgkio_escape(struct dxgprocess *process, void *__user inargs)
{
@@ -4438,14 +4560,17 @@ dxgkio_escape(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
- if (ret < 0) {
- adapter = NULL;
+ if (ret < 0)
goto cleanup;
- }
adapter_locked = true;
args.adapter = adapter->host_handle;
- ret = dxgvmb_send_escape(process, adapter, &args);
+
+ if (args.type == _D3DKMT_ESCAPE_DRIVERPRIVATE &&
+ args.flags.driver_known_escape)
+ ret = driver_known_escape(process, adapter, &args);
+ else
+ ret = dxgvmb_send_escape(process, adapter, &args, true);
cleanup:
@@ -4485,10 +4610,8 @@ dxgkio_query_vidmem_info(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
- if (ret < 0) {
- adapter = NULL;
+ if (ret < 0)
goto cleanup;
- }
adapter_locked = true;
args.adapter = adapter->host_handle;
@@ -5323,9 +5446,9 @@ dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs)
{
struct d3dkmt_isfeatureenabled args;
struct dxgadapter *adapter = NULL;
- struct dxgglobal *dxgglobal = dxggbl();
struct d3dkmt_isfeatureenabled *__user uargs = inargs;
int ret;
+ bool adapter_locked = false;
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
@@ -5340,11 +5463,10 @@ dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs)
goto cleanup;
}
- if (adapter) {
- ret = dxgadapter_acquire_lock_shared(adapter);
- if (ret < 0)
- goto cleanup;
- }
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0)
+ goto cleanup;
+ adapter_locked = true;
ret = dxgvmb_send_is_feature_enabled(adapter, &args);
if (ret)
@@ -5354,10 +5476,10 @@ dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs)
cleanup:
- if (adapter) {
+ if (adapter_locked)
dxgadapter_release_lock_shared(adapter);
+ if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
- }
DXG_TRACE_IOCTL_END(ret);
return ret;
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index 5b345ddaf66e..db40e8ff40b0 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -237,6 +237,37 @@ struct d3dddi_destroypagingqueue {
struct d3dkmthandle paging_queue;
};
+enum d3dddi_knownescapetype {
+ _D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE = 0,
+ _D3DDDI_DRIVERESCAPETYPE_TRANSLATERESOURCEHANDLE = 1,
+ _D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE = 2,
+ _D3DDDI_DRIVERESCAPETYPE_BUILDTESTCOMMANDBUFFER = 3,
+};
+
+struct d3dddi_translate_allocation_handle {
+ enum d3dddi_knownescapetype escape_type;
+ struct d3dkmthandle allocation;
+};
+
+struct d3dddi_testcommand {
+ char buffer[72];
+};
+
+#define D3DDDI_MAXTESTBUFFERSIZE 4096
+#define D3DDDI_MAXTESTBUFFERPRIVATEDRIVERDATASIZE 1024
+
+struct d3dddi_buildtestcommandbuffer {
+ enum d3dddi_knownescapetype escape_type;
+ struct d3dkmthandle device;
+ struct d3dkmthandle context;
+ __u32 flags;
+ struct d3dddi_testcommand command;
+ void *dma_buffer;
+ void *dma_buffer_priv_data;
+ __u32 dma_buffer_size;
+ __u32 dma_buffer_priv_data_size;
+};
+
enum d3dkmt_escapetype {
_D3DKMT_ESCAPE_DRIVERPRIVATE = 0,
_D3DKMT_ESCAPE_VIDMM = 1,
^ permalink raw reply related
* [PATCH 43/55] drivers: hv: dxgkrnl: Implement D3DDKMTIsFeatureEnabled API
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
D3DKMTIsFeatureEnabled is used to query if a particular feature is
supported by the given adapter.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 2 ++
drivers/hv/dxgkrnl/dxgvmbus.c | 58 ++++++++++++++++++++++++++++++++---
drivers/hv/dxgkrnl/dxgvmbus.h | 31 +++++++++++++++++++
drivers/hv/dxgkrnl/ioctl.c | 46 +++++++++++++++++++++++++++
include/uapi/misc/d3dkmthk.h | 31 ++++++++++++++++++-
5 files changed, 163 insertions(+), 5 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 90bcd5377744..ebf81cffa289 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -994,6 +994,8 @@ int dxgvmb_send_share_object_with_host(struct dxgprocess *process,
int dxgvmb_send_invalidate_cache(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_invalidatecache *args);
+int dxgvmb_send_is_feature_enabled(struct dxgadapter *adapter,
+ struct d3dkmt_isfeatureenabled *args);
void signal_host_cpu_event(struct dxghostevent *eventhdr);
int ntstatus2int(struct ntstatus status);
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 916ed9071656..2436e1a7bc73 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -135,15 +135,16 @@ static int init_message_res(struct dxgvmbusmsgres *msg,
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;
+ if (adapter)
+ 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
+ if (adapter && !dxgglobal->async_msg_enabled)
msg->channel = &adapter->channel;
+ else
+ msg->channel = &dxgglobal->channel;
return 0;
}
@@ -2049,6 +2050,55 @@ int dxgvmb_send_invalidate_cache(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_is_feature_enabled(struct dxgadapter *adapter,
+ struct d3dkmt_isfeatureenabled *args)
+{
+ int ret;
+ struct dxgkvmb_command_isfeatureenabled_return *result;
+ struct dxgvmbusmsgres msg = {.hdr = NULL};
+ int res_size = sizeof(*result);
+
+ if (adapter) {
+ struct dxgkvmb_command_isfeatureenabled *command;
+
+ ret = init_message_res(&msg, adapter, sizeof(*command),
+ res_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ command->feature_id = args->feature_id;
+ result = msg.res;
+ command_vgpu_to_host_init1(&command->hdr,
+ DXGK_VMBCOMMAND_ISFEATUREENABLED);
+ } else {
+ struct dxgkvmb_command_isfeatureenabled_gbl *command;
+
+ ret = init_message_res(&msg, adapter, sizeof(*command),
+ res_size);
+ if (ret)
+ goto cleanup;
+ command = (void *)msg.msg;
+ command->feature_id = args->feature_id;
+ result = msg.res;
+ command_vm_to_host_init1(&command->hdr,
+ DXGK_VMBCOMMAND_ISFEATUREENABLED_GLOBAL);
+ }
+ ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+ result, res_size);
+ if (ret == 0) {
+ ret = ntstatus2int(result->status);
+ if (ret == 0)
+ args->result = result->result;
+ goto cleanup;
+ }
+
+cleanup:
+ free_message((struct dxgvmbusmsg *)&msg);
+ if (ret)
+ DXG_TRACE("err: %d", ret);
+ return ret;
+}
+
int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_queryallocationresidency
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index 20c562b485de..a7e625b2f896 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -48,6 +48,7 @@ enum dxgkvmb_commandtype_global {
DXGK_VMBCOMMAND_SETIOSPACEREGION = 1010,
DXGK_VMBCOMMAND_COMPLETETRANSACTION = 1011,
DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST = 1021,
+ DXGK_VMBCOMMAND_ISFEATUREENABLED_GLOBAL = 1022,
DXGK_VMBCOMMAND_INVALID_VM_TO_HOST
};
@@ -126,6 +127,7 @@ enum dxgkvmb_commandtype {
DXGK_VMBCOMMAND_LOGEVENT = 65,
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES = 66,
DXGK_VMBCOMMAND_INVALIDATECACHE = 67,
+ DXGK_VMBCOMMAND_ISFEATUREENABLED = 68,
DXGK_VMBCOMMAND_INVALID
};
@@ -871,6 +873,35 @@ struct dxgkvmb_command_shareobjectwithhost_return {
u64 vail_nt_handle;
};
+struct dxgk_feature_desc {
+ u16 min_supported_version;
+ u16 max_supported_version;
+ struct {
+ u16 supported : 1;
+ u16 virtualization_mode : 3;
+ u16 global : 1;
+ u16 driver_feature : 1;
+ u16 internal : 1;
+ u16 reserved : 9;
+ };
+};
+
+struct dxgkvmb_command_isfeatureenabled {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ enum dxgk_feature_id feature_id;
+};
+
+struct dxgkvmb_command_isfeatureenabled_gbl {
+ struct dxgkvmb_command_vm_to_host hdr;
+ enum dxgk_feature_id feature_id;
+};
+
+struct dxgkvmb_command_isfeatureenabled_return {
+ struct ntstatus status;
+ struct dxgk_feature_desc descriptor;
+ struct dxgk_isfeatureenabled_result result;
+};
+
int
dxgvmb_send_sync_msg(struct dxgvmbuschannel *channel,
void *command, u32 command_size, void *result,
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 24b84be2fb73..5ff4b27af19d 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -5318,6 +5318,51 @@ dxgkio_enum_processes(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_isfeatureenabled args;
+ struct dxgadapter *adapter = NULL;
+ struct dxgglobal *dxgglobal = dxggbl();
+ struct d3dkmt_isfeatureenabled *__user uargs = inargs;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ adapter = dxgprocess_adapter_by_handle(process, args.adapter);
+ if (adapter == NULL) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (adapter) {
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0)
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_is_feature_enabled(adapter, &args);
+ if (ret)
+ goto cleanup;
+
+ ret = copy_to_user(&uargs->result, &args.result, sizeof(args.result));
+
+cleanup:
+
+ if (adapter) {
+ dxgadapter_release_lock_shared(adapter);
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ }
+
+ DXG_TRACE_IOCTL_END(ret);
+ return ret;
+}
+
static struct ioctl_desc ioctls[] = {
/* 0x00 */ {},
/* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID},
@@ -5406,6 +5451,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x47 */ {dxgkio_open_syncobj_from_syncfile,
LX_DXOPENSYNCOBJECTFROMSYNCFILE},
/* 0x48 */ {dxgkio_enum_processes, LX_DXENUMPROCESSES},
+/* 0x49 */ {dxgkio_is_feature_enabled, LX_ISFEATUREENABLED},
};
/*
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index f9f817060fa9..5b345ddaf66e 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -1580,7 +1580,7 @@ struct d3dkmt_opensyncobjectfromsyncfile {
__u64 fence_value_gpu_va; /* out */
};
- struct d3dkmt_enumprocesses {
+struct d3dkmt_enumprocesses {
struct winluid adapter_luid;
#ifdef __KERNEL__
__u32 *buffer;
@@ -1590,6 +1590,33 @@ struct d3dkmt_opensyncobjectfromsyncfile {
__u64 buffer_count;
};
+enum dxgk_feature_id {
+ _DXGK_FEATURE_HWSCH = 0,
+ _DXGK_FEATURE_PAGE_BASED_MEMORY_MANAGER = 32,
+ _DXGK_FEATURE_KERNEL_MODE_TESTING = 33,
+ _DXGK_FEATURE_MAX
+};
+
+struct dxgk_isfeatureenabled_result {
+ __u16 version;
+ union {
+ struct {
+ __u16 enabled : 1;
+ __u16 known_feature : 1;
+ __u16 supported_by_driver : 1;
+ __u16 supported_on_config : 1;
+ __u16 reserved : 12;
+ };
+ __u16 value;
+ };
+};
+
+struct d3dkmt_isfeatureenabled {
+ struct d3dkmthandle adapter;
+ enum dxgk_feature_id feature_id;
+ struct dxgk_isfeatureenabled_result result;
+};
+
struct d3dkmt_invalidatecache {
struct d3dkmthandle device;
struct d3dkmthandle allocation;
@@ -1730,5 +1757,7 @@ struct d3dkmt_invalidatecache {
_IOWR(0x47, 0x47, struct d3dkmt_opensyncobjectfromsyncfile)
#define LX_DXENUMPROCESSES \
_IOWR(0x47, 0x48, struct d3dkmt_enumprocesses)
+#define LX_ISFEATUREENABLED \
+ _IOWR(0x47, 0x49, struct d3dkmt_isfeatureenabled)
#endif /* _D3DKMTHK_H */
^ permalink raw reply related
* [PATCH 42/55] drivers: hv: dxgkrnl: Implement the D3DKMTEnumProcesses API
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
D3DKMTEnumProcesses is used to enumerate PIDs for all processes,
which opened the /dev/dxg device.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 1 +
drivers/hv/dxgkrnl/dxgprocess.c | 2 +
drivers/hv/dxgkrnl/ioctl.c | 81 +++++++++++++++++++++++++++++++++
include/uapi/misc/d3dkmthk.h | 12 +++++
4 files changed, 96 insertions(+)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 6af1e59b0a31..90bcd5377744 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -387,6 +387,7 @@ struct dxgprocess {
pid_t pid;
pid_t tgid;
pid_t vpid; /* pdi from the current namespace */
+ struct pid_namespace *nspid; /* namespace id */
/* how many time the process was opened */
struct kref process_kref;
/* protects the object memory */
diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgprocess.c
index 5a4c4cb0c2e8..9bfd53df1a54 100644
--- a/drivers/hv/dxgkrnl/dxgprocess.c
+++ b/drivers/hv/dxgkrnl/dxgprocess.c
@@ -13,6 +13,7 @@
#include "dxgkrnl.h"
#include "linux/sched.h"
+#include <linux/pid_namespace.h>
#undef dev_fmt
#define dev_fmt(fmt) "dxgk: " fmt
@@ -33,6 +34,7 @@ struct dxgprocess *dxgprocess_create(void)
process->pid = current->pid;
process->tgid = current->tgid;
process->vpid = task_pid_vnr(current);
+ process->nspid = task_active_pid_ns(current);
ret = dxgvmb_send_create_process(process);
if (ret < 0) {
DXG_TRACE("send_create_process failed");
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 466bef6c14b3..24b84be2fb73 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/anon_inodes.h>
#include <linux/mman.h>
+#include <linux/pid_namespace.h>
#include "dxgkrnl.h"
#include "dxgvmbus.h"
@@ -5238,6 +5239,85 @@ dxgkio_share_object_with_host(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgkio_enum_processes(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_enumprocesses args;
+ struct d3dkmt_enumprocesses *__user input = inargs;
+ struct dxgadapter *adapter = NULL;
+ struct dxgadapter *entry;
+ struct dxgglobal *dxgglobal = dxggbl();
+ struct dxgprocess_adapter *pentry;
+ int nump = 0; /* Current number of processes*/
+ struct ntstatus status;
+ int ret;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ if (args.buffer_count == 0) {
+ DXG_ERR("Invalid buffer count");
+ 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 (*(u64 *) &entry->luid == *(u64 *) &args.adapter_luid) {
+ adapter = entry;
+ break;
+ }
+ }
+
+ if (adapter == NULL) {
+ DXG_ERR("Failed to find dxgadapter");
+ ret = -EINVAL;
+ goto cleanup_locks;
+ }
+
+ list_for_each_entry(pentry, &adapter->adapter_process_list_head,
+ adapter_process_list_entry) {
+ if (pentry->process->nspid != task_active_pid_ns(current))
+ continue;
+ if (nump == args.buffer_count) {
+ status.v = STATUS_BUFFER_TOO_SMALL;
+ ret = ntstatus2int(status);
+ goto cleanup_locks;
+ }
+ ret = copy_to_user(&args.buffer[nump], &pentry->process->vpid,
+ sizeof(u32));
+ if (ret) {
+ DXG_ERR("failed to copy data to user");
+ ret = -EFAULT;
+ goto cleanup_locks;
+ }
+ nump++;
+ }
+
+cleanup_locks:
+
+ dxgglobal_release_process_adapter_lock();
+ dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED);
+
+ if (ret == 0) {
+ ret = copy_to_user(&input->buffer_count, &nump, sizeof(u32));
+ if (ret)
+ DXG_ERR("failed to copy buffer count to user");
+ }
+
+cleanup:
+
+ DXG_TRACE_IOCTL_END(ret);
+ return ret;
+}
+
static struct ioctl_desc ioctls[] = {
/* 0x00 */ {},
/* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID},
@@ -5325,6 +5405,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x46 */ {dxgkio_wait_sync_file, LX_DXWAITSYNCFILE},
/* 0x47 */ {dxgkio_open_syncobj_from_syncfile,
LX_DXOPENSYNCOBJECTFROMSYNCFILE},
+/* 0x48 */ {dxgkio_enum_processes, LX_DXENUMPROCESSES},
};
/*
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index 84fa07a46d3c..f9f817060fa9 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -1580,6 +1580,16 @@ struct d3dkmt_opensyncobjectfromsyncfile {
__u64 fence_value_gpu_va; /* out */
};
+ struct d3dkmt_enumprocesses {
+ struct winluid adapter_luid;
+#ifdef __KERNEL__
+ __u32 *buffer;
+#else
+ __u64 buffer;
+#endif
+ __u64 buffer_count;
+};
+
struct d3dkmt_invalidatecache {
struct d3dkmthandle device;
struct d3dkmthandle allocation;
@@ -1718,5 +1728,7 @@ struct d3dkmt_invalidatecache {
_IOWR(0x47, 0x46, struct d3dkmt_waitsyncfile)
#define LX_DXOPENSYNCOBJECTFROMSYNCFILE \
_IOWR(0x47, 0x47, struct d3dkmt_opensyncobjectfromsyncfile)
+#define LX_DXENUMPROCESSES \
+ _IOWR(0x47, 0x48, struct d3dkmt_enumprocesses)
#endif /* _D3DKMTHK_H */
^ permalink raw reply related
* [PATCH 41/55] drivers: hv: dxgkrnl: Handle process ID in D3DKMTQueryStatistics
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
When D3DKMTQueryStatistics specifies a non-zero process ID, it needs to be
translated to the host process handle before sending a message to the host.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 3 +-
drivers/hv/dxgkrnl/dxgprocess.c | 2 +
drivers/hv/dxgkrnl/dxgvmbus.c | 140 ++++++++++++++++----------------
drivers/hv/dxgkrnl/ioctl.c | 39 ++++++++-
4 files changed, 111 insertions(+), 73 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index e7d8919b3c01..6af1e59b0a31 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -386,6 +386,7 @@ struct dxgprocess {
struct list_head plistentry;
pid_t pid;
pid_t tgid;
+ pid_t vpid; /* pdi from the current namespace */
/* how many time the process was opened */
struct kref process_kref;
/* protects the object memory */
@@ -981,7 +982,7 @@ 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,
+int dxgvmb_send_query_statistics(struct d3dkmthandle host_process_handle,
struct dxgadapter *adapter,
struct d3dkmt_querystatistics *args);
int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgprocess.c
index fd51fd968049..5a4c4cb0c2e8 100644
--- a/drivers/hv/dxgkrnl/dxgprocess.c
+++ b/drivers/hv/dxgkrnl/dxgprocess.c
@@ -12,6 +12,7 @@
*/
#include "dxgkrnl.h"
+#include "linux/sched.h"
#undef dev_fmt
#define dev_fmt(fmt) "dxgk: " fmt
@@ -31,6 +32,7 @@ struct dxgprocess *dxgprocess_create(void)
DXG_TRACE("new dxgprocess created");
process->pid = current->pid;
process->tgid = current->tgid;
+ process->vpid = task_pid_vnr(current);
ret = dxgvmb_send_create_process(process);
if (ret < 0) {
DXG_TRACE("send_create_process failed");
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 487804ca731a..916ed9071656 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -22,6 +22,8 @@
#include "dxgkrnl.h"
#include "dxgvmbus.h"
+#pragma GCC diagnostic ignored "-Warray-bounds"
+
#undef dev_fmt
#define dev_fmt(fmt) "dxgk: " fmt
@@ -113,7 +115,6 @@ static int init_message(struct dxgvmbusmsg *msg, struct dxgadapter *adapter,
static int init_message_res(struct dxgvmbusmsgres *msg,
struct dxgadapter *adapter,
- struct dxgprocess *process,
u32 size,
u32 result_size)
{
@@ -146,7 +147,7 @@ static int init_message_res(struct dxgvmbusmsgres *msg,
return 0;
}
-static void free_message(struct dxgvmbusmsg *msg, struct dxgprocess *process)
+static void free_message(struct dxgvmbusmsg *msg)
{
if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
vfree(msg->hdr);
@@ -646,7 +647,7 @@ int dxgvmb_send_set_iospace_region(u64 start, u64 len)
dxgglobal_release_channel_lock();
cleanup:
- free_message(&msg, NULL);
+ free_message(&msg);
if (ret)
DXG_TRACE("Error: %d", ret);
return ret;
@@ -699,7 +700,7 @@ int dxgvmb_send_create_process(struct dxgprocess *process)
dxgglobal_release_channel_lock();
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -727,7 +728,7 @@ int dxgvmb_send_destroy_process(struct d3dkmthandle process)
dxgglobal_release_channel_lock();
cleanup:
- free_message(&msg, NULL);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -790,7 +791,7 @@ int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -839,7 +840,7 @@ int dxgvmb_send_open_sync_object(struct dxgprocess *process,
*syncobj = result.sync_object;
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -881,7 +882,7 @@ int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -912,7 +913,7 @@ int dxgvmb_send_destroy_nt_shared_object(struct d3dkmthandle shared_handle)
dxgglobal_release_channel_lock();
cleanup:
- free_message(&msg, NULL);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -945,7 +946,7 @@ int dxgvmb_send_destroy_sync_object(struct dxgprocess *process,
dxgglobal_release_channel_lock();
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -989,7 +990,7 @@ int dxgvmb_send_share_object_with_host(struct dxgprocess *process,
args->object_vail_nt_handle = result.vail_nt_handle;
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_ERR("err: %d", ret);
return ret;
@@ -1026,7 +1027,7 @@ int dxgvmb_send_open_adapter(struct dxgadapter *adapter)
adapter->host_handle = result.host_adapter_handle;
cleanup:
- free_message(&msg, NULL);
+ free_message(&msg);
if (ret)
DXG_ERR("Failed to open adapter: %d", ret);
return ret;
@@ -1048,7 +1049,7 @@ int dxgvmb_send_close_adapter(struct dxgadapter *adapter)
ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
NULL, 0);
- free_message(&msg, NULL);
+ free_message(&msg);
if (ret)
DXG_ERR("Failed to close adapter: %d", ret);
return ret;
@@ -1084,7 +1085,7 @@ int dxgvmb_send_get_internal_adapter_info(struct dxgadapter *adapter)
sizeof(adapter->device_instance_id) / sizeof(u16));
dxgglobal->async_msg_enabled = result.async_msg_enabled != 0;
}
- free_message(&msg, NULL);
+ free_message(&msg);
if (ret)
DXG_ERR("Failed to get adapter info: %d", ret);
return ret;
@@ -1114,7 +1115,7 @@ struct d3dkmthandle dxgvmb_send_create_device(struct dxgadapter *adapter,
&result, sizeof(result));
if (ret < 0)
result.device.v = 0;
- free_message(&msg, process);
+ free_message(&msg);
cleanup:
if (ret)
DXG_TRACE("err: %d", ret);
@@ -1140,7 +1141,7 @@ int dxgvmb_send_destroy_device(struct dxgadapter *adapter,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1167,7 +1168,7 @@ int dxgvmb_send_flush_device(struct dxgdevice *device,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1239,7 +1240,7 @@ dxgvmb_send_create_context(struct dxgadapter *adapter,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return context;
@@ -1265,7 +1266,7 @@ int dxgvmb_send_destroy_context(struct dxgadapter *adapter,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1312,7 +1313,7 @@ int dxgvmb_send_create_paging_queue(struct dxgprocess *process,
pqueue->handle = args->paging_queue;
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1339,7 +1340,7 @@ int dxgvmb_send_destroy_paging_queue(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, NULL, 0);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1550,7 +1551,7 @@ int create_existing_sysmem(struct dxgdevice *device,
cleanup:
if (kmem)
vunmap(kmem);
- free_message(&msg, device->process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1783,7 +1784,7 @@ create_local_allocations(struct dxgprocess *process,
dxgdevice_release_alloc_list_lock(device);
}
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1908,7 +1909,7 @@ int dxgvmb_send_create_allocation(struct dxgprocess *process,
if (result)
vfree(result);
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
@@ -1950,7 +1951,7 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess *process,
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -1992,7 +1993,7 @@ int dxgvmb_send_query_clock_calibration(struct dxgprocess *process,
ret = ntstatus2int(result.status);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2015,7 +2016,7 @@ int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process,
process->host_handle);
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2042,7 +2043,7 @@ int dxgvmb_send_invalidate_cache(struct dxgprocess *process,
command->length = args->length;
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2078,7 +2079,7 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
}
result_size += result_allocation_size;
- ret = init_message_res(&msg, adapter, process, cmd_size, result_size);
+ ret = init_message_res(&msg, adapter, cmd_size, result_size);
if (ret)
goto cleanup;
command = (void *)msg.msg;
@@ -2115,7 +2116,7 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
}
cleanup:
- free_message((struct dxgvmbusmsg *)&msg, process);
+ free_message((struct dxgvmbusmsg *)&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2179,7 +2180,7 @@ int dxgvmb_send_escape(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2243,7 +2244,7 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2288,7 +2289,7 @@ int dxgvmb_send_get_device_state(struct dxgprocess *process,
args->execution_state = result.args.execution_state;
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2312,8 +2313,7 @@ int dxgvmb_send_open_resource(struct dxgprocess *process,
sizeof(*result);
struct dxgvmbusmsgres msg = {.hdr = NULL};
- ret = init_message_res(&msg, adapter, process, sizeof(*command),
- result_size);
+ ret = init_message_res(&msg, adapter, sizeof(*command), result_size);
if (ret)
goto cleanup;
command = msg.msg;
@@ -2342,7 +2342,7 @@ int dxgvmb_send_open_resource(struct dxgprocess *process,
alloc_handles[i] = handles[i];
cleanup:
- free_message((struct dxgvmbusmsg *)&msg, process);
+ free_message((struct dxgvmbusmsg *)&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2367,7 +2367,7 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
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,
+ ret = init_message_res(&msg, device->adapter,
sizeof(*command), result_size);
if (ret)
goto cleanup;
@@ -2427,7 +2427,7 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
cleanup:
- free_message((struct dxgvmbusmsg *)&msg, device->process);
+ free_message((struct dxgvmbusmsg *)&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2479,7 +2479,7 @@ int dxgvmb_send_make_resident(struct dxgprocess *process,
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2525,7 +2525,7 @@ int dxgvmb_send_evict(struct dxgprocess *process,
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2580,7 +2580,7 @@ int dxgvmb_send_submit_command(struct dxgprocess *process,
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2617,7 +2617,7 @@ int dxgvmb_send_map_gpu_va(struct dxgprocess *process,
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2647,7 +2647,7 @@ int dxgvmb_send_reserve_gpu_va(struct dxgprocess *process,
args->virtual_address = result.virtual_address;
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2674,7 +2674,7 @@ int dxgvmb_send_free_gpu_va(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2730,7 +2730,7 @@ int dxgvmb_send_update_gpu_va(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2816,7 +2816,7 @@ dxgvmb_send_create_sync_object(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2910,7 +2910,7 @@ int dxgvmb_send_signal_sync_object(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -2970,7 +2970,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3023,7 +3023,7 @@ int dxgvmb_send_wait_sync_object_gpu(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3103,7 +3103,7 @@ int dxgvmb_send_lock2(struct dxgprocess *process,
hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3130,7 +3130,7 @@ int dxgvmb_send_unlock2(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3175,7 +3175,7 @@ int dxgvmb_send_update_alloc_property(struct dxgprocess *process,
}
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3200,7 +3200,7 @@ int dxgvmb_send_mark_device_as_error(struct dxgprocess *process,
command->args = *args;
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3270,7 +3270,7 @@ int dxgvmb_send_set_allocation_priority(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3312,7 +3312,7 @@ int dxgvmb_send_get_allocation_priority(struct dxgprocess *process,
}
result_size = sizeof(*result) + priority_size;
- ret = init_message_res(&msg, adapter, process, cmd_size, result_size);
+ ret = init_message_res(&msg, adapter, cmd_size, result_size);
if (ret)
goto cleanup;
command = (void *)msg.msg;
@@ -3352,7 +3352,7 @@ int dxgvmb_send_get_allocation_priority(struct dxgprocess *process,
}
cleanup:
- free_message((struct dxgvmbusmsg *)&msg, process);
+ free_message((struct dxgvmbusmsg *)&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3381,7 +3381,7 @@ int dxgvmb_send_set_context_sch_priority(struct dxgprocess *process,
command->in_process = in_process;
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3415,7 +3415,7 @@ int dxgvmb_send_get_context_sch_priority(struct dxgprocess *process,
*priority = result.priority;
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3461,7 +3461,7 @@ int dxgvmb_send_offer_allocations(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3486,7 +3486,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess *process,
result_size += (args->allocation_count - 1) *
sizeof(enum d3dddi_reclaim_result);
- ret = init_message_res(&msg, adapter, process, cmd_size, result_size);
+ ret = init_message_res(&msg, adapter, cmd_size, result_size);
if (ret)
goto cleanup;
command = (void *)msg.msg;
@@ -3537,7 +3537,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess *process,
}
cleanup:
- free_message((struct dxgvmbusmsg *)&msg, process);
+ free_message((struct dxgvmbusmsg *)&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3567,7 +3567,7 @@ int dxgvmb_send_change_vidmem_reservation(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3706,7 +3706,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
dxgvmb_send_destroy_hwqueue(process, adapter,
command->hwqueue);
}
- free_message(&msg, process);
+ free_message(&msg);
return ret;
}
@@ -3731,7 +3731,7 @@ int dxgvmb_send_destroy_hwqueue(struct dxgprocess *process,
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3815,7 +3815,7 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
@@ -3873,13 +3873,13 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process,
}
cleanup:
- free_message(&msg, process);
+ free_message(&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
}
-int dxgvmb_send_query_statistics(struct dxgprocess *process,
+int dxgvmb_send_query_statistics(struct d3dkmthandle host_process_handle,
struct dxgadapter *adapter,
struct d3dkmt_querystatistics *args)
{
@@ -3888,7 +3888,7 @@ int dxgvmb_send_query_statistics(struct dxgprocess *process,
int ret;
struct dxgvmbusmsgres msg = {.hdr = NULL};
- ret = init_message_res(&msg, adapter, process, sizeof(*command),
+ ret = init_message_res(&msg, adapter, sizeof(*command),
sizeof(*result));
if (ret)
goto cleanup;
@@ -3897,7 +3897,7 @@ int dxgvmb_send_query_statistics(struct dxgprocess *process,
command_vgpu_to_host_init2(&command->hdr,
DXGK_VMBCOMMAND_QUERYSTATISTICS,
- process->host_handle);
+ host_process_handle);
command->args = *args;
ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
@@ -3909,7 +3909,7 @@ int dxgvmb_send_query_statistics(struct dxgprocess *process,
ret = ntstatus2int(result->status);
cleanup:
- free_message((struct dxgvmbusmsg *)&msg, process);
+ free_message((struct dxgvmbusmsg *)&msg);
if (ret)
DXG_TRACE("err: %d", ret);
return ret;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 56b838a87f09..466bef6c14b3 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -147,6 +147,23 @@ static int dxgkio_open_adapter_from_luid(struct dxgprocess *process,
return ret;
}
+static struct d3dkmthandle find_dxgprocess_handle(u64 pid)
+{
+ struct dxgglobal *dxgglobal = dxggbl();
+ struct dxgprocess *entry;
+ struct d3dkmthandle host_handle = {};
+
+ mutex_lock(&dxgglobal->plistmutex);
+ list_for_each_entry(entry, &dxgglobal->plisthead, plistentry) {
+ if (entry->vpid == pid) {
+ host_handle.v = entry->host_handle.v;
+ break;
+ }
+ }
+ mutex_unlock(&dxgglobal->plistmutex);
+ return host_handle;
+}
+
static int dxgkio_query_statistics(struct dxgprocess *process,
void __user *inargs)
{
@@ -156,6 +173,8 @@ static int dxgkio_query_statistics(struct dxgprocess *process,
struct dxgadapter *adapter = NULL;
struct winluid tmp;
struct dxgglobal *dxgglobal = dxggbl();
+ struct d3dkmthandle host_process_handle = process->host_handle;
+ u64 pid;
args = vzalloc(sizeof(struct d3dkmt_querystatistics));
if (args == NULL) {
@@ -170,6 +189,18 @@ static int dxgkio_query_statistics(struct dxgprocess *process,
goto cleanup;
}
+ /* Find the host process handle when needed */
+ pid = args->process;
+ if (pid) {
+ host_process_handle = find_dxgprocess_handle(pid);
+ if (host_process_handle.v == 0) {
+ DXG_ERR("Invalid process ID is specified: %lld", pid);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ args->process = 0;
+ }
+
dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED);
list_for_each_entry(entry, &dxgglobal->adapter_list_head,
adapter_list_entry) {
@@ -186,7 +217,8 @@ static int dxgkio_query_statistics(struct dxgprocess *process,
if (adapter) {
tmp = args->adapter_luid;
args->adapter_luid = adapter->host_adapter_luid;
- ret = dxgvmb_send_query_statistics(process, adapter, args);
+ ret = dxgvmb_send_query_statistics(host_process_handle, adapter,
+ args);
if (ret >= 0) {
args->adapter_luid = tmp;
ret = copy_to_user(inargs, args, sizeof(*args));
@@ -280,7 +312,10 @@ dxgkp_enum_adapters(struct dxgprocess *process,
dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED);
if (adapter_count > adapter_count_max) {
- ret = STATUS_BUFFER_TOO_SMALL;
+ struct ntstatus status;
+
+ status.v = STATUS_BUFFER_TOO_SMALL;
+ ret = ntstatus2int(status);
DXG_TRACE("Too many adapters");
ret = copy_to_user(adapter_count_out,
&dxgglobal->num_adapters, sizeof(u32));
^ permalink raw reply related
* [PATCH 40/55] drivers: hv: dxgkrnl: Added implementation for D3DKMTInvalidateCache
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
D3DKMTInvalidateCache is called by user mode drivers when the device
doesn't support cache coherent access to compute device allocations.
It needs to be called after an allocation was accessed by CPU and now
needs to be accessed by the device. And vice versa.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 3 +++
drivers/hv/dxgkrnl/dxgvmbus.c | 27 +++++++++++++++++++
drivers/hv/dxgkrnl/dxgvmbus.h | 11 ++++++++
drivers/hv/dxgkrnl/ioctl.c | 49 +++++++++++++++++++++++++++++++++--
include/uapi/misc/d3dkmthk.h | 9 +++++++
5 files changed, 97 insertions(+), 2 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index d20489317c0b..e7d8919b3c01 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -989,6 +989,9 @@ int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
u32 cmd_size);
int dxgvmb_send_share_object_with_host(struct dxgprocess *process,
struct d3dkmt_shareobjectwithhost *args);
+int dxgvmb_send_invalidate_cache(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_invalidatecache *args);
void signal_host_cpu_event(struct dxghostevent *eventhdr);
int ntstatus2int(struct ntstatus status);
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 5f17efc937c3..487804ca731a 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -2021,6 +2021,33 @@ int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_invalidate_cache(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dkmt_invalidatecache *args)
+{
+ struct dxgkvmb_command_invalidatecache *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_INVALIDATECACHE,
+ process->host_handle);
+ command->device = args->device;
+ command->allocation = args->allocation;
+ command->offset = args->offset;
+ command->length = args->length;
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ DXG_TRACE("err: %d", ret);
+ return ret;
+}
+
int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_queryallocationresidency
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index b4a98f7c2522..20c562b485de 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -125,6 +125,7 @@ enum dxgkvmb_commandtype {
DXGK_VMBCOMMAND_QUERYRESOURCEINFO = 64,
DXGK_VMBCOMMAND_LOGEVENT = 65,
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES = 66,
+ DXGK_VMBCOMMAND_INVALIDATECACHE = 67,
DXGK_VMBCOMMAND_INVALID
};
@@ -428,6 +429,16 @@ struct dxgkvmb_command_flushheaptransitions {
struct dxgkvmb_command_vgpu_to_host hdr;
};
+/* Returns ntstatus */
+struct dxgkvmb_command_invalidatecache {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ struct d3dkmthandle device;
+ struct d3dkmthandle allocation;
+ u64 offset;
+ u64 length;
+ u64 reserved;
+};
+
struct dxgkvmb_command_freegpuvirtualaddress {
struct dxgkvmb_command_vgpu_to_host hdr;
struct d3dkmt_freegpuvirtualaddress args;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index f735b18fcc14..56b838a87f09 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -4286,6 +4286,8 @@ dxgkio_query_clock_calibration(struct dxgprocess *process, void *__user inargs)
dxgadapter_release_lock_shared(adapter);
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
+
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4333,6 +4335,49 @@ dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user inargs)
dxgadapter_release_lock_shared(adapter);
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
+
+ DXG_TRACE_IOCTL_END(ret);
+ return ret;
+}
+
+static int
+dxgkio_invalidate_cache(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_invalidatecache args;
+ int ret;
+ struct dxgdevice *device = NULL;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EFAULT;
+ 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 = dxgvmb_send_invalidate_cache(process, device->adapter,
+ &args);
+
+cleanup:
+
+ if (device) {
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -5198,7 +5243,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x22 */ {dxgkio_get_context_scheduling_priority,
LX_DXGETCONTEXTSCHEDULINGPRIORITY},
/* 0x23 */ {},
-/* 0x24 */ {},
+/* 0x24 */ {dxgkio_invalidate_cache, LX_DXINVALIDATECACHE},
/* 0x25 */ {dxgkio_lock2, LX_DXLOCK2},
/* 0x26 */ {dxgkio_mark_device_as_error, LX_DXMARKDEVICEASERROR},
/* 0x27 */ {dxgkio_offer_allocations, LX_DXOFFERALLOCATIONS},
@@ -5243,7 +5288,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST},
/* 0x45 */ {dxgkio_create_sync_file, LX_DXCREATESYNCFILE},
/* 0x46 */ {dxgkio_wait_sync_file, LX_DXWAITSYNCFILE},
-/* 0x46 */ {dxgkio_open_syncobj_from_syncfile,
+/* 0x47 */ {dxgkio_open_syncobj_from_syncfile,
LX_DXOPENSYNCOBJECTFROMSYNCFILE},
};
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index 1eaa3f038322..84fa07a46d3c 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -1580,6 +1580,13 @@ struct d3dkmt_opensyncobjectfromsyncfile {
__u64 fence_value_gpu_va; /* out */
};
+struct d3dkmt_invalidatecache {
+ struct d3dkmthandle device;
+ struct d3dkmthandle allocation;
+ __u64 offset;
+ __u64 length;
+};
+
/*
* Dxgkrnl Graphics Port Driver ioctl definitions
*
@@ -1647,6 +1654,8 @@ struct d3dkmt_opensyncobjectfromsyncfile {
_IOWR(0x47, 0x21, struct d3dkmt_getcontextinprocessschedulingpriority)
#define LX_DXGETCONTEXTSCHEDULINGPRIORITY \
_IOWR(0x47, 0x22, struct d3dkmt_getcontextschedulingpriority)
+#define LX_DXINVALIDATECACHE \
+ _IOWR(0x47, 0x24, struct d3dkmt_invalidatecache)
#define LX_DXLOCK2 \
_IOWR(0x47, 0x25, struct d3dkmt_lock2)
#define LX_DXMARKDEVICEASERROR \
^ permalink raw reply related
* [PATCH 39/55] drivers: hv: dxgkrnl: Added support for compute only adapters
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 1 +
drivers/hv/dxgkrnl/dxgmodule.c | 11 ++++++++++-
drivers/hv/dxgkrnl/dxgvmbus.c | 1 +
drivers/hv/dxgkrnl/ioctl.c | 4 ++++
4 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index c5ed23cb90df..d20489317c0b 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -478,6 +478,7 @@ struct dxgadapter {
struct winluid luid; /* VM bus channel luid */
u16 device_description[80];
u16 device_instance_id[WIN_MAX_PATH];
+ bool compute_only;
bool stopping_adapter;
};
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index f419597f711a..0fafb6167229 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -20,6 +20,7 @@
#define PCI_VENDOR_ID_MICROSOFT 0x1414
#define PCI_DEVICE_ID_VIRTUAL_RENDER 0x008E
+#define PCI_DEVICE_ID_COMPUTE_ACCELERATOR 0x008A
#undef pr_fmt
#define pr_fmt(fmt) "dxgk: " fmt
@@ -270,6 +271,8 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
adapter->adapter_state = DXGADAPTER_STATE_WAITING_VMBUS;
adapter->host_vgpu_luid = host_vgpu_luid;
+ if (dev->device == PCI_DEVICE_ID_COMPUTE_ACCELERATOR)
+ adapter->compute_only = true;
kref_init(&adapter->adapter_kref);
init_rwsem(&adapter->core_lock);
mutex_init(&adapter->device_creation_lock);
@@ -622,6 +625,12 @@ static struct pci_device_id dxg_pci_id_table[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID
},
+ {
+ .vendor = PCI_VENDOR_ID_MICROSOFT,
+ .device = PCI_DEVICE_ID_COMPUTE_ACCELERATOR,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID
+ },
{ 0 }
};
@@ -962,4 +971,4 @@ module_exit(dxg_drv_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Microsoft Dxgkrnl virtual compute device Driver");
-MODULE_VERSION("2.0.1");
+MODULE_VERSION("2.0.2");
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index eb3f4c5153a6..5f17efc937c3 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -3774,6 +3774,7 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
adapter_type->indirect_display_device = 0;
adapter_type->acg_supported = 0;
adapter_type->support_set_timings_from_vidpn = 0;
+ adapter_type->compute_only = !!adapter->compute_only;
break;
}
default:
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 98350583943e..f735b18fcc14 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -254,6 +254,8 @@ dxgkp_enum_adapters(struct dxgprocess *process,
list_for_each_entry(entry, &dxgglobal->adapter_list_head,
adapter_list_entry) {
+ if (entry->compute_only && !filter.include_compute_only)
+ continue;
if (dxgadapter_acquire_lock_shared(entry) == 0) {
struct d3dkmt_adapterinfo *inf = &info[adapter_count];
@@ -474,6 +476,8 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *__user inargs)
list_for_each_entry(entry, &dxgglobal->adapter_list_head,
adapter_list_entry) {
+ if (entry->compute_only)
+ continue;
if (dxgadapter_acquire_lock_shared(entry) == 0) {
struct d3dkmt_adapterinfo *inf = &info[adapter_count];
^ permalink raw reply related
* [PATCH 38/55] drivers: hv: dxgkrnl: Fixed dxgkrnl to build for the 6.1 kernel
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Definition for GPADL was changed from u32 to struct vmbus_gpadl.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 8 --------
drivers/hv/dxgkrnl/dxgkrnl.h | 4 ----
drivers/hv/dxgkrnl/dxgvmbus.c | 8 --------
3 files changed, 20 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index d9d45bd4a31e..bcd19b7267d1 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -927,19 +927,11 @@ void dxgallocation_destroy(struct dxgallocation *alloc)
alloc->owner.device,
&args, &alloc->alloc_handle);
}
-#ifdef _MAIN_KERNEL_
if (alloc->gpadl.gpadl_handle) {
DXG_TRACE("Teardown gpadl %d", alloc->gpadl.gpadl_handle);
vmbus_teardown_gpadl(dxgglobal_get_vmbus(), &alloc->gpadl);
alloc->gpadl.gpadl_handle = 0;
}
-#else
- if (alloc->gpadl) {
- DXG_TRACE("Teardown gpadl %d", alloc->gpadl);
- vmbus_teardown_gpadl(dxgglobal_get_vmbus(), alloc->gpadl);
- alloc->gpadl = 0;
- }
-#endif
if (alloc->priv_drv_data)
vfree(alloc->priv_drv_data);
if (alloc->cpu_address_mapped)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 1b40d6e39085..c5ed23cb90df 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -728,11 +728,7 @@ struct dxgallocation {
u32 cached:1;
u32 handle_valid:1;
/* GPADL address list for existing sysmem allocations */
-#ifdef _MAIN_KERNEL_
struct vmbus_gpadl gpadl;
-#else
- u32 gpadl;
-#endif
/* Number of pages in the 'pages' array */
u32 num_pages;
/*
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 8c99f141482e..eb3f4c5153a6 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1493,22 +1493,14 @@ int create_existing_sysmem(struct dxgdevice *device,
ret = -ENOMEM;
goto cleanup;
}
-#ifdef _MAIN_KERNEL_
DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle);
-#else
- DXG_TRACE("New gpadl %d", dxgalloc->gpadl);
-#endif
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;
-#ifdef _MAIN_KERNEL_
set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
-#else
- set_store_command->gpadl = dxgalloc->gpadl;
-#endif
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
msg.size);
if (ret < 0)
^ permalink raw reply related
* [PATCH 37/55] drivers: hv: dxgkrnl: Added missed NULL check for resource object
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/ioctl.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 69324510c9e2..98350583943e 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -1589,7 +1589,8 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
&process->handle_table,
HMGRENTRY_TYPE_DXGRESOURCE,
args.resource);
- kref_get(&resource->resource_kref);
+ if (resource != NULL)
+ kref_get(&resource->resource_kref);
dxgprocess_ht_lock_shared_up(process);
if (resource == NULL || resource->device != device) {
@@ -1693,10 +1694,8 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
&standard_alloc);
cleanup:
- if (resource_mutex_acquired) {
+ 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++) {
@@ -1727,6 +1726,9 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
if (adapter)
dxgadapter_release_lock_shared(adapter);
+ if (resource && !args.flags.create_resource)
+ kref_put(&resource->resource_kref, dxgresource_release);
+
if (device) {
dxgdevice_release_lock_shared(device);
kref_put(&device->device_kref, dxgdevice_release);
^ permalink raw reply related
* [PATCH 36/55] drivers: hv: dxgkrnl: Close shared file objects in case of a failure
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/ioctl.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 7c72790f917f..69324510c9e2 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -4536,7 +4536,7 @@ enum dxg_sharedobject_type {
};
static int get_object_fd(enum dxg_sharedobject_type type,
- void *object, int *fdout)
+ void *object, int *fdout, struct file **filp)
{
struct file *file;
int fd;
@@ -4565,8 +4565,8 @@ static int get_object_fd(enum dxg_sharedobject_type type,
return -ENOTRECOVERABLE;
}
- fd_install(fd, file);
*fdout = fd;
+ *filp = file;
return 0;
}
@@ -4581,6 +4581,7 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
struct dxgsharedresource *shared_resource = NULL;
struct d3dkmthandle *handles = NULL;
int object_fd = -1;
+ struct file *filp = NULL;
void *obj = NULL;
u32 handle_size;
int ret;
@@ -4660,7 +4661,7 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
switch (object_type) {
case HMGRENTRY_TYPE_DXGSYNCOBJECT:
ret = get_object_fd(DXG_SHARED_SYNCOBJECT, shared_syncobj,
- &object_fd);
+ &object_fd, &filp);
if (ret < 0) {
DXG_ERR("get_object_fd failed for sync object");
goto cleanup;
@@ -4675,7 +4676,7 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
break;
case HMGRENTRY_TYPE_DXGRESOURCE:
ret = get_object_fd(DXG_SHARED_RESOURCE, shared_resource,
- &object_fd);
+ &object_fd, &filp);
if (ret < 0) {
DXG_ERR("get_object_fd failed for resource");
goto cleanup;
@@ -4708,10 +4709,15 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
if (ret) {
DXG_ERR("failed to copy shared handle");
ret = -EFAULT;
+ goto cleanup;
}
+ fd_install(object_fd, filp);
+
cleanup:
if (ret < 0) {
+ if (filp)
+ fput(filp);
if (object_fd >= 0)
put_unused_fd(object_fd);
}
^ permalink raw reply related
* [PATCH 35/55] drivers: hv: dxgkrnl: Fix synchronization locks
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 19 ++++----
drivers/hv/dxgkrnl/dxgkrnl.h | 8 +++-
drivers/hv/dxgkrnl/dxgmodule.c | 3 +-
drivers/hv/dxgkrnl/dxgprocess.c | 11 +++--
drivers/hv/dxgkrnl/dxgvmbus.c | 85 +++++++++++++++++++++++----------
drivers/hv/dxgkrnl/ioctl.c | 24 ++++++----
drivers/hv/dxgkrnl/misc.h | 1 +
7 files changed, 101 insertions(+), 50 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index 3d8bec295b87..d9d45bd4a31e 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -136,7 +136,7 @@ void dxgadapter_release(struct kref *refcount)
struct dxgadapter *adapter;
adapter = container_of(refcount, struct dxgadapter, adapter_kref);
- DXG_TRACE("%p", adapter);
+ DXG_TRACE("Destroying adapter: %px", adapter);
kfree(adapter);
}
@@ -270,6 +270,8 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
if (ret < 0) {
kref_put(&device->device_kref, dxgdevice_release);
device = NULL;
+ } else {
+ DXG_TRACE("dxgdevice created: %px", device);
}
}
return device;
@@ -413,11 +415,8 @@ void dxgdevice_destroy(struct dxgdevice *device)
cleanup:
- if (device->adapter) {
+ if (device->adapter)
dxgprocess_adapter_remove_device(device);
- kref_put(&device->adapter->adapter_kref, dxgadapter_release);
- device->adapter = NULL;
- }
up_write(&device->device_lock);
@@ -721,6 +720,8 @@ void dxgdevice_release(struct kref *refcount)
struct dxgdevice *device;
device = container_of(refcount, struct dxgdevice, device_kref);
+ DXG_TRACE("Destroying device: %px", device);
+ kref_put(&device->adapter->adapter_kref, dxgadapter_release);
kfree(device);
}
@@ -999,6 +1000,9 @@ void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue)
kfree(pqueue);
}
+/*
+ * Process_adapter_mutex is held.
+ */
struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
struct dxgadapter *adapter)
{
@@ -1108,7 +1112,7 @@ int dxgprocess_adapter_add_device(struct dxgprocess *process,
void dxgprocess_adapter_remove_device(struct dxgdevice *device)
{
- DXG_TRACE("Removing device: %p", device);
+ DXG_TRACE("Removing device: %px", device);
mutex_lock(&device->adapter_info->device_list_mutex);
if (device->device_list_entry.next) {
list_del(&device->device_list_entry);
@@ -1147,8 +1151,7 @@ void dxgsharedsyncobj_release(struct kref *refcount)
if (syncobj->adapter) {
dxgadapter_remove_shared_syncobj(syncobj->adapter,
syncobj);
- kref_put(&syncobj->adapter->adapter_kref,
- dxgadapter_release);
+ kref_put(&syncobj->adapter->adapter_kref, dxgadapter_release);
}
kfree(syncobj);
}
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index f63aa6f7a9dc..1b40d6e39085 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -404,7 +404,10 @@ struct dxgprocess {
/* Handle of the corresponding objec on the host */
struct d3dkmthandle host_handle;
- /* List of opened adapters (dxgprocess_adapter) */
+ /*
+ * List of opened adapters (dxgprocess_adapter).
+ * Protected by process_adapter_mutex.
+ */
struct list_head process_adapter_list_head;
};
@@ -451,6 +454,8 @@ enum dxgadapter_state {
struct dxgadapter {
struct rw_semaphore core_lock;
struct kref adapter_kref;
+ /* Protects creation and destruction of dxgdevice objects */
+ struct mutex device_creation_lock;
/* Entry in the list of adapters in dxgglobal */
struct list_head adapter_list_entry;
/* The list of dxgprocess_adapter entries */
@@ -997,6 +1002,7 @@ void dxgk_validate_ioctls(void);
#define DXG_TRACE(fmt, ...) do { \
trace_printk(dev_fmt(fmt) "\n", ##__VA_ARGS__); \
+ dev_dbg(DXGDEV, "%s: " fmt, __func__, ##__VA_ARGS__); \
} while (0)
#define DXG_ERR(fmt, ...) do { \
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index aa27931a3447..f419597f711a 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -272,6 +272,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
adapter->host_vgpu_luid = host_vgpu_luid;
kref_init(&adapter->adapter_kref);
init_rwsem(&adapter->core_lock);
+ mutex_init(&adapter->device_creation_lock);
INIT_LIST_HEAD(&adapter->adapter_process_list_head);
INIT_LIST_HEAD(&adapter->shared_resource_list_head);
@@ -961,4 +962,4 @@ module_exit(dxg_drv_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Microsoft Dxgkrnl virtual compute device Driver");
-MODULE_VERSION("2.0.0");
+MODULE_VERSION("2.0.1");
diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgprocess.c
index e77e3a4983f8..fd51fd968049 100644
--- a/drivers/hv/dxgkrnl/dxgprocess.c
+++ b/drivers/hv/dxgkrnl/dxgprocess.c
@@ -214,14 +214,15 @@ int dxgprocess_close_adapter(struct dxgprocess *process,
hmgrtable_unlock(&process->local_handle_table, DXGLOCK_EXCL);
if (adapter) {
+ mutex_lock(&adapter->device_creation_lock);
+ dxgglobal_acquire_process_adapter_lock();
adapter_info = dxgprocess_get_adapter_info(process, adapter);
- if (adapter_info) {
- dxgglobal_acquire_process_adapter_lock();
+ if (adapter_info)
dxgprocess_adapter_release(adapter_info);
- dxgglobal_release_process_adapter_lock();
- } else {
+ else
ret = -EINVAL;
- }
+ dxgglobal_release_process_adapter_lock();
+ mutex_unlock(&adapter->device_creation_lock);
} else {
DXG_ERR("Adapter not found %x", handle.v);
ret = -EINVAL;
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 566ccb6d01c9..8c99f141482e 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1573,8 +1573,27 @@ process_allocation_handles(struct dxgprocess *process,
struct dxgresource *resource)
{
int ret = 0;
- int i;
+ int i = 0;
+ int k;
+ struct dxgkvmb_command_allocinfo_return *host_alloc;
+ /*
+ * Assign handle to the internal objects, so VM bus messages will be
+ * sent to the host to free them during object destruction.
+ */
+ if (args->flags.create_resource)
+ resource->handle = res->resource;
+ for (i = 0; i < args->alloc_count; i++) {
+ host_alloc = &res->allocation_info[i];
+ dxgalloc[i]->alloc_handle = host_alloc->allocation;
+ }
+
+ /*
+ * Assign handle to the handle table.
+ * In case of a failure all handles should be freed.
+ * When the function returns, the objects could be destroyed by
+ * handle immediately.
+ */
hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
if (args->flags.create_resource) {
ret = hmgrtable_assign_handle(&process->handle_table, resource,
@@ -1583,14 +1602,12 @@ process_allocation_handles(struct dxgprocess *process,
if (ret < 0) {
DXG_ERR("failed to assign resource handle %x",
res->resource.v);
+ goto cleanup;
} 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],
@@ -1602,9 +1619,26 @@ process_allocation_handles(struct dxgprocess *process,
args->alloc_count, i);
break;
}
- dxgalloc[i]->alloc_handle = host_alloc->allocation;
dxgalloc[i]->handle_valid = 1;
}
+ if (ret < 0) {
+ if (args->flags.create_resource) {
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGRESOURCE,
+ res->resource);
+ resource->handle_valid = 0;
+ }
+ for (k = 0; k < i; k++) {
+ host_alloc = &res->allocation_info[i];
+ hmgrtable_free_handle(&process->handle_table,
+ HMGRENTRY_TYPE_DXGALLOCATION,
+ host_alloc->allocation);
+ dxgalloc[i]->handle_valid = 0;
+ }
+ }
+
+cleanup:
+
hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
if (ret)
@@ -1705,18 +1739,17 @@ create_local_allocations(struct dxgprocess *process,
}
}
- 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) {
DXG_ERR("failed to copy global share");
ret = -EFAULT;
+ goto cleanup;
}
+ ret = process_allocation_handles(process, device, args, result,
+ dxgalloc, resource);
+
cleanup:
if (ret < 0) {
@@ -3576,22 +3609,6 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
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);
@@ -3641,6 +3658,22 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
}
}
+ ret = hmgrtable_assign_handle_safe(&process->handle_table,
+ NULL,
+ HMGRENTRY_TYPE_MONITOREDFENCE,
+ command->hwqueue_progress_fence);
+ if (ret < 0)
+ goto cleanup;
+
+ hwqueue->progress_fence_sync_object = command->hwqueue_progress_fence;
+ hwqueue->handle = command->hwqueue;
+
+ ret = hmgrtable_assign_handle_safe(&process->handle_table, hwqueue,
+ HMGRENTRY_TYPE_DXGHWQUEUE,
+ command->hwqueue);
+ if (ret < 0)
+ hwqueue->handle.v = 0;
+
cleanup:
if (ret < 0) {
DXG_ERR("failed %x", ret);
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 3dc9e76f4f3d..7c72790f917f 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -636,6 +636,7 @@ dxgkio_create_device(struct dxgprocess *process, void *__user inargs)
struct dxgdevice *device = NULL;
struct d3dkmthandle host_device_handle = {};
bool adapter_locked = false;
+ bool device_creation_locked = false;
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
@@ -651,6 +652,9 @@ dxgkio_create_device(struct dxgprocess *process, void *__user inargs)
goto cleanup;
}
+ mutex_lock(&adapter->device_creation_lock);
+ device_creation_locked = true;
+
device = dxgdevice_create(adapter, process);
if (device == NULL) {
ret = -ENOMEM;
@@ -699,6 +703,9 @@ dxgkio_create_device(struct dxgprocess *process, void *__user inargs)
if (adapter_locked)
dxgadapter_release_lock_shared(adapter);
+ if (device_creation_locked)
+ mutex_unlock(&adapter->device_creation_lock);
+
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
@@ -803,22 +810,21 @@ dxgkio_create_context_virtual(struct dxgprocess *process, void *__user inargs)
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) {
DXG_ERR("failed to copy context handle");
ret = -EFAULT;
+ goto cleanup;
}
+ 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);
} else {
DXG_ERR("invalid host handle");
ret = -EINVAL;
diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h
index ee2ebfdd1c13..9fcab4ae2c0c 100644
--- a/drivers/hv/dxgkrnl/misc.h
+++ b/drivers/hv/dxgkrnl/misc.h
@@ -38,6 +38,7 @@ extern const struct d3dkmthandle zerohandle;
* core_lock (dxgadapter lock)
* device_lock (dxgdevice lock)
* process_adapter_mutex
+ * device_creation_lock in dxgadapter
* adapter_list_lock
* device_mutex (dxgglobal mutex)
*/
^ permalink raw reply related
* [PATCH 34/55] drivers: hv: dxgkrnl: Improve tracing and return values from copy from user
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 17 +-
drivers/hv/dxgkrnl/dxgmodule.c | 1 +
drivers/hv/dxgkrnl/dxgsyncfile.c | 13 +-
drivers/hv/dxgkrnl/dxgvmbus.c | 98 ++++-----
drivers/hv/dxgkrnl/ioctl.c | 327 +++++++++++++++----------------
5 files changed, 225 insertions(+), 231 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index d92e1348ccfb..f63aa6f7a9dc 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -999,18 +999,25 @@ void dxgk_validate_ioctls(void);
trace_printk(dev_fmt(fmt) "\n", ##__VA_ARGS__); \
} while (0)
-#define DXG_ERR(fmt, ...) do { \
- dev_err(DXGDEV, fmt, ##__VA_ARGS__); \
- trace_printk("*** dxgkerror *** " dev_fmt(fmt) "\n", ##__VA_ARGS__); \
+#define DXG_ERR(fmt, ...) do { \
+ dev_err(DXGDEV, "%s: " fmt, __func__, ##__VA_ARGS__); \
+ trace_printk("*** dxgkerror *** " dev_fmt(fmt) "\n", ##__VA_ARGS__); \
} while (0)
#else
#define DXG_TRACE(...)
-#define DXG_ERR(fmt, ...) do { \
- dev_err(DXGDEV, fmt, ##__VA_ARGS__); \
+#define DXG_ERR(fmt, ...) do { \
+ dev_err(DXGDEV, "%s: " fmt, __func__, ##__VA_ARGS__); \
} while (0)
#endif /* DEBUG */
+#define DXG_TRACE_IOCTL_END(ret) do { \
+ if (ret < 0) \
+ DXG_ERR("Ioctl failed: %d", ret); \
+ else \
+ DXG_TRACE("Ioctl returned: %d", ret); \
+} while (0)
+
#endif
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index 5570f35954d4..aa27931a3447 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -961,3 +961,4 @@ module_exit(dxg_drv_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Microsoft Dxgkrnl virtual compute device Driver");
+MODULE_VERSION("2.0.0");
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.c b/drivers/hv/dxgkrnl/dxgsyncfile.c
index 9d5832c90ad7..f3b3e8dd4568 100644
--- a/drivers/hv/dxgkrnl/dxgsyncfile.c
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.c
@@ -38,13 +38,6 @@
#undef dev_fmt
#define dev_fmt(fmt) "dxgk: " fmt
-#ifdef DEBUG
-static char *errorstr(int ret)
-{
- return ret < 0 ? "err" : "";
-}
-#endif
-
static const struct dma_fence_ops dxgdmafence_ops;
static struct dxgsyncpoint *to_syncpoint(struct dma_fence *fence)
@@ -193,7 +186,7 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
if (fd >= 0)
put_unused_fd(fd);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -317,7 +310,7 @@ int dxgkio_open_syncobj_from_syncfile(struct dxgprocess *process,
kref_put(&device->device_kref, dxgdevice_release);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -415,7 +408,7 @@ int dxgkio_wait_sync_file(struct dxgprocess *process, void *__user inargs)
if (dmafence)
dma_fence_put(dmafence);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 36f4d4e84d3e..566ccb6d01c9 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1212,7 +1212,7 @@ dxgvmb_send_create_context(struct dxgadapter *adapter,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("Faled to copy private data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -1230,7 +1230,7 @@ dxgvmb_send_create_context(struct dxgadapter *adapter,
if (ret) {
DXG_ERR(
"Faled to copy private data to user");
- ret = -EINVAL;
+ ret = -EFAULT;
dxgvmb_send_destroy_context(adapter, process,
context);
context.v = 0;
@@ -1365,7 +1365,7 @@ copy_private_data(struct d3dkmt_createallocation *args,
args->private_runtime_data_size);
if (ret) {
DXG_ERR("failed to copy runtime data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
private_data_dest += args->private_runtime_data_size;
@@ -1385,7 +1385,7 @@ copy_private_data(struct d3dkmt_createallocation *args,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy private data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
private_data_dest += args->priv_drv_data_size;
@@ -1406,7 +1406,7 @@ copy_private_data(struct d3dkmt_createallocation *args,
input_alloc->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy alloc data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
private_data_dest += input_alloc->priv_drv_data_size;
@@ -1658,7 +1658,7 @@ create_local_allocations(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy resource handle");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -1690,7 +1690,7 @@ create_local_allocations(struct dxgprocess *process,
host_alloc->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy private data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
alloc_private_data += host_alloc->priv_drv_data_size;
@@ -1700,7 +1700,7 @@ create_local_allocations(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy alloc handle");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -1714,7 +1714,7 @@ create_local_allocations(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy global share");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -1961,7 +1961,7 @@ int dxgvmb_send_query_clock_calibration(struct dxgprocess *process,
sizeof(result.clock_data));
if (ret) {
DXG_ERR("failed to copy clock data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = ntstatus2int(result.status);
@@ -2041,7 +2041,7 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
alloc_size);
if (ret) {
DXG_ERR("failed to copy alloc handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -2059,7 +2059,7 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
result_allocation_size);
if (ret) {
DXG_ERR("failed to copy residency status");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -2105,7 +2105,7 @@ int dxgvmb_send_escape(struct dxgprocess *process,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy priv data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -2164,14 +2164,14 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess *process,
sizeof(output->budget));
if (ret) {
DXG_ERR("failed to copy budget");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(&output->current_usage, &result.current_usage,
sizeof(output->current_usage));
if (ret) {
DXG_ERR("failed to copy current usage");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(&output->current_reservation,
@@ -2179,7 +2179,7 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess *process,
sizeof(output->current_reservation));
if (ret) {
DXG_ERR("failed to copy reservation");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(&output->available_for_reservation,
@@ -2187,7 +2187,7 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess *process,
sizeof(output->available_for_reservation));
if (ret) {
DXG_ERR("failed to copy avail reservation");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -2229,7 +2229,7 @@ int dxgvmb_send_get_device_state(struct dxgprocess *process,
ret = copy_to_user(output, &result.args, sizeof(result.args));
if (ret) {
DXG_ERR("failed to copy output args");
- ret = -EINVAL;
+ ret = -EFAULT;
}
if (args->state_type == _D3DKMT_DEVICESTATE_EXECUTION)
@@ -2404,7 +2404,7 @@ int dxgvmb_send_make_resident(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy alloc handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
command_vgpu_to_host_init2(&command->hdr,
@@ -2454,7 +2454,7 @@ int dxgvmb_send_evict(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy alloc handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
command_vgpu_to_host_init2(&command->hdr,
@@ -2502,14 +2502,14 @@ int dxgvmb_send_submit_command(struct dxgprocess *process,
hbufsize);
if (ret) {
DXG_ERR(" failed to copy history buffer");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_from_user((u8 *) &command[1] + hbufsize,
args->priv_drv_data, args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy history priv data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2671,7 +2671,7 @@ int dxgvmb_send_update_gpu_va(struct dxgprocess *process,
op_size);
if (ret) {
DXG_ERR("failed to copy operations");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2751,7 +2751,7 @@ dxgvmb_send_create_sync_object(struct dxgprocess *process,
sizeof(u64));
if (ret) {
DXG_ERR("failed to read fence");
- ret = -EINVAL;
+ ret = -EFAULT;
} else {
DXG_TRACE("fence value:%lx",
value);
@@ -2820,7 +2820,7 @@ int dxgvmb_send_signal_sync_object(struct dxgprocess *process,
if (ret) {
DXG_ERR("Failed to read objects %p %d",
objects, object_size);
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
current_pos += object_size;
@@ -2834,7 +2834,7 @@ int dxgvmb_send_signal_sync_object(struct dxgprocess *process,
if (ret) {
DXG_ERR("Failed to read contexts %p %d",
contexts, context_size);
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
current_pos += context_size;
@@ -2844,7 +2844,7 @@ int dxgvmb_send_signal_sync_object(struct dxgprocess *process,
if (ret) {
DXG_ERR("Failed to read fences %p %d",
fences, fence_size);
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -2898,7 +2898,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
ret = copy_from_user(current_pos, args->objects, object_size);
if (ret) {
DXG_ERR("failed to copy objects");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
current_pos += object_size;
@@ -2906,7 +2906,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
fence_size);
if (ret) {
DXG_ERR("failed to copy fences");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
} else {
@@ -3037,7 +3037,7 @@ int dxgvmb_send_lock2(struct dxgprocess *process,
sizeof(args->data));
if (ret) {
DXG_ERR("failed to copy data");
- ret = -EINVAL;
+ ret = -EFAULT;
alloc->cpu_address_refcount--;
if (alloc->cpu_address_refcount == 0) {
dxg_unmap_iospace(alloc->cpu_address,
@@ -3119,7 +3119,7 @@ int dxgvmb_send_update_alloc_property(struct dxgprocess *process,
sizeof(u64));
if (ret1) {
DXG_ERR("failed to copy paging fence");
- ret = -EINVAL;
+ ret = -EFAULT;
}
}
cleanup:
@@ -3204,14 +3204,14 @@ int dxgvmb_send_set_allocation_priority(struct dxgprocess *process,
alloc_size);
if (ret) {
DXG_ERR("failed to copy alloc handle");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_from_user((u8 *) allocations + alloc_size,
args->priorities, priority_size);
if (ret) {
DXG_ERR("failed to copy alloc priority");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3277,7 +3277,7 @@ int dxgvmb_send_get_allocation_priority(struct dxgprocess *process,
alloc_size);
if (ret) {
DXG_ERR("failed to copy alloc handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3296,7 +3296,7 @@ int dxgvmb_send_get_allocation_priority(struct dxgprocess *process,
priority_size);
if (ret) {
DXG_ERR("failed to copy priorities");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -3402,7 +3402,7 @@ int dxgvmb_send_offer_allocations(struct dxgprocess *process,
}
if (ret) {
DXG_ERR("failed to copy input handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3457,7 +3457,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess *process,
}
if (ret) {
DXG_ERR("failed to copy input handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3469,7 +3469,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess *process,
&result->paging_fence_value, sizeof(u64));
if (ret) {
DXG_ERR("failed to copy paging fence");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3480,7 +3480,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess *process,
args->allocation_count);
if (ret) {
DXG_ERR("failed to copy results");
- ret = -EINVAL;
+ ret = -EFAULT;
}
}
@@ -3559,7 +3559,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy private data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -3604,7 +3604,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy hwqueue handle");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(&inargs->queue_progress_fence,
@@ -3612,7 +3612,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to progress fence");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(&inargs->queue_progress_fence_cpu_va,
@@ -3620,7 +3620,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
sizeof(inargs->queue_progress_fence_cpu_va));
if (ret) {
DXG_ERR("failed to copy fence cpu va");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(&inargs->queue_progress_fence_gpu_va,
@@ -3628,7 +3628,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
sizeof(u64));
if (ret) {
DXG_ERR("failed to copy fence gpu va");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
if (args->priv_drv_data_size) {
@@ -3637,7 +3637,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *process,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy private data");
- ret = -EINVAL;
+ ret = -EFAULT;
}
}
@@ -3706,7 +3706,7 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
args->private_data, args->private_data_size);
if (ret) {
DXG_ERR("Faled to copy private data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3758,7 +3758,7 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
args->private_data_size);
if (ret) {
DXG_ERR("Faled to copy private data to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -3791,7 +3791,7 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process,
primaries_size);
if (ret) {
DXG_ERR("failed to copy primaries handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -3801,7 +3801,7 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy primaries data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 622904d5c3a9..3dc9e76f4f3d 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -29,13 +29,6 @@ struct ioctl_desc {
u32 ioctl;
};
-#ifdef DEBUG
-static char *errorstr(int ret)
-{
- return ret < 0 ? "err" : "";
-}
-#endif
-
void dxgsharedsyncobj_put(struct dxgsharedsyncobject *syncobj)
{
DXG_TRACE("Release syncobj: %p", syncobj);
@@ -108,7 +101,7 @@ static int dxgkio_open_adapter_from_luid(struct dxgprocess *process,
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("Faled to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -129,7 +122,7 @@ static int dxgkio_open_adapter_from_luid(struct dxgprocess *process,
&args.adapter_handle,
sizeof(struct d3dkmthandle));
if (ret)
- ret = -EINVAL;
+ ret = -EFAULT;
}
adapter = entry;
}
@@ -150,7 +143,7 @@ static int dxgkio_open_adapter_from_luid(struct dxgprocess *process,
if (ret < 0)
dxgprocess_close_adapter(process, args.adapter_handle);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -173,7 +166,7 @@ static int dxgkio_query_statistics(struct dxgprocess *process,
ret = copy_from_user(args, inargs, sizeof(*args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -199,7 +192,7 @@ static int dxgkio_query_statistics(struct dxgprocess *process,
ret = copy_to_user(inargs, args, sizeof(*args));
if (ret) {
DXG_ERR("failed to copy args");
- ret = -EINVAL;
+ ret = -EFAULT;
}
}
dxgadapter_release_lock_shared(adapter);
@@ -209,7 +202,7 @@ static int dxgkio_query_statistics(struct dxgprocess *process,
if (args)
vfree(args);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -233,7 +226,7 @@ dxgkp_enum_adapters(struct dxgprocess *process,
&dxgglobal->num_adapters, sizeof(u32));
if (ret) {
DXG_ERR("copy_to_user faled");
- ret = -EINVAL;
+ ret = -EFAULT;
}
goto cleanup;
}
@@ -291,7 +284,7 @@ dxgkp_enum_adapters(struct dxgprocess *process,
&dxgglobal->num_adapters, sizeof(u32));
if (ret) {
DXG_ERR("copy_to_user failed");
- ret = -EINVAL;
+ ret = -EFAULT;
}
goto cleanup;
}
@@ -300,13 +293,13 @@ dxgkp_enum_adapters(struct dxgprocess *process,
sizeof(adapter_count));
if (ret) {
DXG_ERR("failed to copy adapter_count");
- ret = -EINVAL;
+ ret = -EFAULT;
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;
+ ret = -EFAULT;
}
cleanup:
@@ -326,7 +319,7 @@ dxgkp_enum_adapters(struct dxgprocess *process,
if (adapters)
vfree(adapters);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -437,7 +430,7 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -447,7 +440,7 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy args to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
goto cleanup;
}
@@ -508,14 +501,14 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy args to user");
- ret = -EINVAL;
+ ret = -EFAULT;
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;
+ ret = -EFAULT;
}
cleanup:
@@ -536,7 +529,7 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *__user inargs)
if (adapters)
vfree(adapters);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -549,7 +542,7 @@ dxgkio_enum_adapters3(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -561,7 +554,7 @@ dxgkio_enum_adapters3(struct dxgprocess *process, void *__user inargs)
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -574,7 +567,7 @@ dxgkio_close_adapter(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -584,7 +577,7 @@ dxgkio_close_adapter(struct dxgprocess *process, void *__user inargs)
cleanup:
- DXG_TRACE("ioctl: %s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -598,7 +591,7 @@ dxgkio_query_adapter_info(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -630,7 +623,7 @@ dxgkio_query_adapter_info(struct dxgprocess *process, void *__user inargs)
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -647,7 +640,7 @@ dxgkio_create_device(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -677,7 +670,7 @@ dxgkio_create_device(struct dxgprocess *process, void *__user inargs)
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy device handle");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -709,7 +702,7 @@ dxgkio_create_device(struct dxgprocess *process, void *__user inargs)
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -724,7 +717,7 @@ dxgkio_destroy_device(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -756,7 +749,7 @@ dxgkio_destroy_device(struct dxgprocess *process, void *__user inargs)
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -774,7 +767,7 @@ dxgkio_create_context_virtual(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -824,7 +817,7 @@ dxgkio_create_context_virtual(struct dxgprocess *process, void *__user inargs)
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy context handle");
- ret = -EINVAL;
+ ret = -EFAULT;
}
} else {
DXG_ERR("invalid host handle");
@@ -851,7 +844,7 @@ dxgkio_create_context_virtual(struct dxgprocess *process, void *__user inargs)
kref_put(&device->device_kref, dxgdevice_release);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -868,7 +861,7 @@ dxgkio_destroy_context(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -920,7 +913,7 @@ dxgkio_destroy_context(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %s %d", errorstr(ret), __func__, ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -938,7 +931,7 @@ dxgkio_create_hwqueue(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1002,7 +995,7 @@ dxgkio_create_hwqueue(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -1019,7 +1012,7 @@ static int dxgkio_destroy_hwqueue(struct dxgprocess *process,
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1070,7 +1063,7 @@ static int dxgkio_destroy_hwqueue(struct dxgprocess *process,
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -1088,7 +1081,7 @@ dxgkio_create_paging_queue(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1128,7 +1121,7 @@ dxgkio_create_paging_queue(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1169,7 +1162,7 @@ dxgkio_create_paging_queue(struct dxgprocess *process, void *__user inargs)
kref_put(&device->device_kref, dxgdevice_release);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -1186,7 +1179,7 @@ dxgkio_destroy_paging_queue(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1247,7 +1240,7 @@ dxgkio_destroy_paging_queue(struct dxgprocess *process, void *__user inargs)
kref_put(&device->device_kref, dxgdevice_release);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -1351,7 +1344,7 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1373,7 +1366,7 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
alloc_info_size);
if (ret) {
DXG_ERR("failed to copy alloc info");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1412,7 +1405,7 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
sizeof(standard_alloc));
if (ret) {
DXG_ERR("failed to copy std alloc data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
if (standard_alloc.type ==
@@ -1556,7 +1549,7 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
if (ret) {
DXG_ERR(
"failed to copy runtime data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -1576,7 +1569,7 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
if (ret) {
DXG_ERR(
"failed to copy res data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -1733,7 +1726,7 @@ dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs)
kref_put(&device->device_kref, dxgdevice_release);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -1793,7 +1786,7 @@ dxgkio_destroy_allocation(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -1823,7 +1816,7 @@ dxgkio_destroy_allocation(struct dxgprocess *process, void *__user inargs)
handle_size);
if (ret) {
DXG_ERR("failed to copy alloc handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -1962,7 +1955,7 @@ dxgkio_destroy_allocation(struct dxgprocess *process, void *__user inargs)
if (allocs)
vfree(allocs);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -1978,7 +1971,7 @@ dxgkio_make_resident(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2022,7 +2015,7 @@ dxgkio_make_resident(struct dxgprocess *process, void *__user inargs)
&args.paging_fence_value, sizeof(u64));
if (ret2) {
DXG_ERR("failed to copy paging fence");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2030,7 +2023,7 @@ dxgkio_make_resident(struct dxgprocess *process, void *__user inargs)
&args.num_bytes_to_trim, sizeof(u64));
if (ret2) {
DXG_ERR("failed to copy bytes to trim");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2041,7 +2034,7 @@ dxgkio_make_resident(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2058,7 +2051,7 @@ dxgkio_evict(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2090,7 +2083,7 @@ dxgkio_evict(struct dxgprocess *process, void *__user inargs)
&args.num_bytes_to_trim, sizeof(u64));
if (ret) {
DXG_ERR("failed to copy bytes to trim to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -2099,7 +2092,7 @@ dxgkio_evict(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2114,7 +2107,7 @@ dxgkio_offer_allocations(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2153,7 +2146,7 @@ dxgkio_offer_allocations(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2169,7 +2162,7 @@ dxgkio_reclaim_allocations(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2212,7 +2205,7 @@ dxgkio_reclaim_allocations(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2227,7 +2220,7 @@ dxgkio_submit_command(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2280,7 +2273,7 @@ dxgkio_submit_command(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2296,7 +2289,7 @@ dxgkio_submit_command_to_hwqueue(struct dxgprocess *process,
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2336,7 +2329,7 @@ dxgkio_submit_command_to_hwqueue(struct dxgprocess *process,
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2352,7 +2345,7 @@ dxgkio_submit_signal_to_hwqueue(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2376,7 +2369,7 @@ dxgkio_submit_signal_to_hwqueue(struct dxgprocess *process, void *__user inargs)
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy hwqueue handle");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2410,7 +2403,7 @@ dxgkio_submit_signal_to_hwqueue(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2428,7 +2421,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2447,7 +2440,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(objects, args.objects, object_size);
if (ret) {
DXG_ERR("failed to copy objects");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2460,7 +2453,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(fences, args.fence_values, object_size);
if (ret) {
DXG_ERR("failed to copy fence values");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2494,7 +2487,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2510,7 +2503,7 @@ dxgkio_map_gpu_va(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2542,7 +2535,7 @@ dxgkio_map_gpu_va(struct dxgprocess *process, void *__user inargs)
&args.paging_fence_value, sizeof(u64));
if (ret2) {
DXG_ERR("failed to copy paging fence to user");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2550,7 +2543,7 @@ dxgkio_map_gpu_va(struct dxgprocess *process, void *__user inargs)
sizeof(args.virtual_address));
if (ret2) {
DXG_ERR("failed to copy va to user");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2561,7 +2554,7 @@ dxgkio_map_gpu_va(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2577,7 +2570,7 @@ dxgkio_reserve_gpu_va(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2614,7 +2607,7 @@ dxgkio_reserve_gpu_va(struct dxgprocess *process, void *__user inargs)
sizeof(args.virtual_address));
if (ret) {
DXG_ERR("failed to copy VA to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -2624,7 +2617,7 @@ dxgkio_reserve_gpu_va(struct dxgprocess *process, void *__user inargs)
kref_put(&adapter->adapter_kref, dxgadapter_release);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2638,7 +2631,7 @@ dxgkio_free_gpu_va(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2680,7 +2673,7 @@ dxgkio_update_gpu_va(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2705,7 +2698,7 @@ dxgkio_update_gpu_va(struct dxgprocess *process, void *__user inargs)
sizeof(args.fence_value));
if (ret) {
DXG_ERR("failed to copy fence value to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -2734,7 +2727,7 @@ dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2808,7 +2801,7 @@ dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy output args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2842,7 +2835,7 @@ dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2856,7 +2849,7 @@ dxgkio_destroy_sync_object(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2885,7 +2878,7 @@ dxgkio_destroy_sync_object(struct dxgprocess *process, void *__user inargs)
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -2906,7 +2899,7 @@ dxgkio_open_sync_object_nt(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -2995,7 +2988,7 @@ dxgkio_open_sync_object_nt(struct dxgprocess *process, void *__user inargs)
if (ret == 0)
goto success;
DXG_ERR("failed to copy output args");
- ret = -EINVAL;
+ ret = -EFAULT;
cleanup:
@@ -3020,7 +3013,7 @@ dxgkio_open_sync_object_nt(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3041,7 +3034,7 @@ dxgkio_signal_sync_object(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3129,7 +3122,7 @@ dxgkio_signal_sync_object(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3144,7 +3137,7 @@ dxgkio_signal_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
if (args.object_count == 0 ||
@@ -3181,7 +3174,7 @@ dxgkio_signal_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3199,7 +3192,7 @@ dxgkio_signal_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3240,7 +3233,7 @@ dxgkio_signal_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3262,7 +3255,7 @@ dxgkio_signal_sync_object_gpu2(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3287,7 +3280,7 @@ dxgkio_signal_sync_object_gpu2(struct dxgprocess *process, void *__user inargs)
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy context handle");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3365,7 +3358,7 @@ dxgkio_signal_sync_object_gpu2(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3380,7 +3373,7 @@ dxgkio_wait_sync_object(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3418,7 +3411,7 @@ dxgkio_wait_sync_object(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3439,7 +3432,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3540,7 +3533,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
kfree(async_host_event);
}
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3563,7 +3556,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3583,7 +3576,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(objects, args.objects, object_size);
if (ret) {
DXG_ERR("failed to copy objects");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3637,7 +3630,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
object_size);
if (ret) {
DXG_ERR("failed to copy fences");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
} else {
@@ -3673,7 +3666,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *process, void *__user inargs)
if (fences && fences != &args.fence_value)
vfree(fences);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3690,7 +3683,7 @@ dxgkio_lock2(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3712,7 +3705,7 @@ dxgkio_lock2(struct dxgprocess *process, void *__user inargs)
alloc->cpu_address_refcount++;
} else {
DXG_ERR("Failed to copy cpu address");
- ret = -EINVAL;
+ ret = -EFAULT;
}
}
}
@@ -3749,7 +3742,7 @@ dxgkio_lock2(struct dxgprocess *process, void *__user inargs)
kref_put(&device->device_kref, dxgdevice_release);
success:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3766,7 +3759,7 @@ dxgkio_unlock2(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3829,7 +3822,7 @@ dxgkio_unlock2(struct dxgprocess *process, void *__user inargs)
kref_put(&device->device_kref, dxgdevice_release);
success:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3844,7 +3837,7 @@ dxgkio_update_alloc_property(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3872,7 +3865,7 @@ dxgkio_update_alloc_property(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3887,7 +3880,7 @@ dxgkio_mark_device_as_error(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
device = dxgprocess_device_by_handle(process, args.device);
@@ -3908,7 +3901,7 @@ dxgkio_mark_device_as_error(struct dxgprocess *process, void *__user inargs)
dxgadapter_release_lock_shared(adapter);
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3923,7 +3916,7 @@ dxgkio_query_alloc_residency(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -3949,7 +3942,7 @@ dxgkio_query_alloc_residency(struct dxgprocess *process, void *__user inargs)
dxgadapter_release_lock_shared(adapter);
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3964,7 +3957,7 @@ dxgkio_set_allocation_priority(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
device = dxgprocess_device_by_handle(process, args.device);
@@ -3984,7 +3977,7 @@ dxgkio_set_allocation_priority(struct dxgprocess *process, void *__user inargs)
dxgadapter_release_lock_shared(adapter);
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -3999,7 +3992,7 @@ dxgkio_get_allocation_priority(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
device = dxgprocess_device_by_handle(process, args.device);
@@ -4019,7 +4012,7 @@ dxgkio_get_allocation_priority(struct dxgprocess *process, void *__user inargs)
dxgadapter_release_lock_shared(adapter);
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4069,14 +4062,14 @@ dxgkio_set_context_scheduling_priority(struct dxgprocess *process,
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = set_context_scheduling_priority(process, args.context,
args.priority, false);
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4111,7 +4104,7 @@ get_context_scheduling_priority(struct dxgprocess *process,
ret = copy_to_user(priority, &pri, sizeof(pri));
if (ret) {
DXG_ERR("failed to copy priority to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -4134,14 +4127,14 @@ dxgkio_get_context_scheduling_priority(struct dxgprocess *process,
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = get_context_scheduling_priority(process, args.context,
&input->priority, false);
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4155,14 +4148,14 @@ dxgkio_set_context_process_scheduling_priority(struct dxgprocess *process,
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
ret = set_context_scheduling_priority(process, args.context,
args.priority, true);
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4176,7 +4169,7 @@ dxgkio_get_context_process_scheduling_priority(struct dxgprocess *process,
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4184,7 +4177,7 @@ dxgkio_get_context_process_scheduling_priority(struct dxgprocess *process,
&((struct d3dkmt_getcontextinprocessschedulingpriority *)
inargs)->priority, true);
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4199,7 +4192,7 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *process, void *__user inargs
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4232,7 +4225,7 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *process, void *__user inargs
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4247,7 +4240,7 @@ dxgkio_query_clock_calibration(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4272,7 +4265,7 @@ dxgkio_query_clock_calibration(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy output args");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -4295,7 +4288,7 @@ dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4319,7 +4312,7 @@ dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy output args");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -4341,7 +4334,7 @@ dxgkio_escape(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4367,7 +4360,7 @@ dxgkio_escape(struct dxgprocess *process, void *__user inargs)
dxgadapter_release_lock_shared(adapter);
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4382,7 +4375,7 @@ dxgkio_query_vidmem_info(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4432,7 +4425,7 @@ dxgkio_get_device_state(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4458,7 +4451,7 @@ dxgkio_get_device_state(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy args to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
goto cleanup;
}
@@ -4590,7 +4583,7 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4610,7 +4603,7 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(handles, args.objects, handle_size);
if (ret) {
DXG_ERR("failed to copy object handles");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4708,7 +4701,7 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(args.shared_handle, &tmp, sizeof(u64));
if (ret) {
DXG_ERR("failed to copy shared handle");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -4726,7 +4719,7 @@ dxgkio_share_objects(struct dxgprocess *process, void *__user inargs)
if (resource)
kref_put(&resource->resource_kref, dxgresource_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4742,7 +4735,7 @@ dxgkio_query_resource_info_nt(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -4795,7 +4788,7 @@ dxgkio_query_resource_info_nt(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy output args");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -4807,7 +4800,7 @@ dxgkio_query_resource_info_nt(struct dxgprocess *process, void *__user inargs)
if (device)
kref_put(&device->device_kref, dxgdevice_release);
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -4859,7 +4852,7 @@ assign_resource_handles(struct dxgprocess *process,
sizeof(open_alloc_info));
if (ret) {
DXG_ERR("failed to copy alloc info");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -5009,7 +5002,7 @@ open_resource(struct dxgprocess *process,
shared_resource->runtime_private_data_size);
if (ret) {
DXG_ERR("failed to copy runtime data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -5020,7 +5013,7 @@ open_resource(struct dxgprocess *process,
shared_resource->resource_private_data_size);
if (ret) {
DXG_ERR("failed to copy resource data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -5031,7 +5024,7 @@ open_resource(struct dxgprocess *process,
shared_resource->alloc_private_data_size);
if (ret) {
DXG_ERR("failed to copy alloc data");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
}
@@ -5046,7 +5039,7 @@ open_resource(struct dxgprocess *process,
sizeof(struct d3dkmthandle));
if (ret) {
DXG_ERR("failed to copy resource handle to user");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -5054,7 +5047,7 @@ open_resource(struct dxgprocess *process,
&args->total_priv_drv_data_size, sizeof(u32));
if (ret) {
DXG_ERR("failed to copy total driver data size");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
@@ -5102,7 +5095,7 @@ dxgkio_open_resource_nt(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -5112,7 +5105,7 @@ dxgkio_open_resource_nt(struct dxgprocess *process, void *__user inargs)
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
@@ -5125,7 +5118,7 @@ dxgkio_share_object_with_host(struct dxgprocess *process, void *__user inargs)
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
DXG_ERR("failed to copy input args");
- ret = -EINVAL;
+ ret = -EFAULT;
goto cleanup;
}
@@ -5138,12 +5131,12 @@ dxgkio_share_object_with_host(struct dxgprocess *process, void *__user inargs)
ret = copy_to_user(inargs, &args, sizeof(args));
if (ret) {
DXG_ERR("failed to copy data to user");
- ret = -EINVAL;
+ ret = -EFAULT;
}
cleanup:
- DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ DXG_TRACE_IOCTL_END(ret);
return ret;
}
^ permalink raw reply related
* [PATCH 33/55] drivers: hv: dxgkrnl: Implement D3DKMTWaitSyncFile
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 11 ++
drivers/hv/dxgkrnl/dxgmodule.c | 7 +-
drivers/hv/dxgkrnl/dxgprocess.c | 12 +-
drivers/hv/dxgkrnl/dxgsyncfile.c | 291 ++++++++++++++++++++++++++++++-
drivers/hv/dxgkrnl/dxgsyncfile.h | 3 +
drivers/hv/dxgkrnl/dxgvmbus.c | 49 ++++++
drivers/hv/dxgkrnl/ioctl.c | 16 +-
include/uapi/misc/d3dkmthk.h | 23 +++
8 files changed, 396 insertions(+), 16 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 3a69e3b34e1c..d92e1348ccfb 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -254,6 +254,10 @@ void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *sharedsyncobj,
struct dxgsyncobject *syncobj);
void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *sharedsyncobj,
struct dxgsyncobject *syncobj);
+int dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj,
+ struct dxgprocess *process,
+ struct d3dkmthandle objecthandle);
+void dxgsharedsyncobj_put(struct dxgsharedsyncobject *syncobj);
struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
struct dxgdevice *device,
@@ -384,6 +388,8 @@ struct dxgprocess {
pid_t tgid;
/* how many time the process was opened */
struct kref process_kref;
+ /* protects the object memory */
+ struct kref process_mem_kref;
/*
* This handle table is used for all objects except dxgadapter
* The handle table lock order is higher than the local_handle_table
@@ -405,6 +411,7 @@ struct dxgprocess {
struct dxgprocess *dxgprocess_create(void);
void dxgprocess_destroy(struct dxgprocess *process);
void dxgprocess_release(struct kref *refcount);
+void dxgprocess_mem_release(struct kref *refcount);
int dxgprocess_open_adapter(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmthandle *handle);
@@ -932,6 +939,10 @@ int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process,
struct d3dkmt_opensyncobjectfromnthandle2
*args,
struct dxgsyncobject *syncobj);
+int dxgvmb_send_open_sync_object(struct dxgprocess *process,
+ struct d3dkmthandle device,
+ struct d3dkmthandle host_shared_syncobj,
+ struct d3dkmthandle *syncobj);
int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_queryallocationresidency
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index 08feae97e845..5570f35954d4 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -149,10 +149,11 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
spin_unlock_irq(&dxgglobal->host_event_list_mutex);
}
-static void signal_dma_fence(struct dxghostevent *eventhdr)
+static void dxg_signal_dma_fence(struct dxghostevent *eventhdr)
{
struct dxgsyncpoint *event = (struct dxgsyncpoint *)eventhdr;
+ DXG_TRACE("syncpoint: %px, fence: %lld", event, event->fence_value);
event->fence_value++;
list_del(&eventhdr->host_event_list_entry);
dma_fence_signal(&event->base);
@@ -198,7 +199,7 @@ void dxgglobal_signal_host_event(u64 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);
+ dxg_signal_dma_fence(event);
else
DXG_ERR("Unknown host event type");
break;
@@ -355,6 +356,7 @@ static struct dxgprocess *dxgglobal_get_current_process(void)
if (entry->tgid == current->tgid) {
if (kref_get_unless_zero(&entry->process_kref)) {
process = entry;
+ kref_get(&entry->process_mem_kref);
DXG_TRACE("found dxgprocess");
} else {
DXG_TRACE("process is destroyed");
@@ -405,6 +407,7 @@ static int dxgk_release(struct inode *n, struct file *f)
return -EINVAL;
kref_put(&process->process_kref, dxgprocess_release);
+ kref_put(&process->process_mem_kref, dxgprocess_mem_release);
f->private_data = NULL;
return 0;
diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgprocess.c
index afef196c0588..e77e3a4983f8 100644
--- a/drivers/hv/dxgkrnl/dxgprocess.c
+++ b/drivers/hv/dxgkrnl/dxgprocess.c
@@ -39,6 +39,7 @@ struct dxgprocess *dxgprocess_create(void)
} else {
INIT_LIST_HEAD(&process->plistentry);
kref_init(&process->process_kref);
+ kref_init(&process->process_mem_kref);
mutex_lock(&dxgglobal->plistmutex);
list_add_tail(&process->plistentry,
@@ -117,8 +118,17 @@ void dxgprocess_release(struct kref *refcount)
dxgprocess_destroy(process);
- if (process->host_handle.v)
+ if (process->host_handle.v) {
dxgvmb_send_destroy_process(process->host_handle);
+ process->host_handle.v = 0;
+ }
+}
+
+void dxgprocess_mem_release(struct kref *refcount)
+{
+ struct dxgprocess *process;
+
+ process = container_of(refcount, struct dxgprocess, process_mem_kref);
kfree(process);
}
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.c b/drivers/hv/dxgkrnl/dxgsyncfile.c
index 88fd78f08fbe..9d5832c90ad7 100644
--- a/drivers/hv/dxgkrnl/dxgsyncfile.c
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.c
@@ -9,6 +9,20 @@
* Dxgkrnl Graphics Driver
* Ioctl implementation
*
+ * dxgsyncpoint:
+ * - pointer to dxgsharedsyncobject
+ * - host_shared_handle_nt_reference incremented
+ * - list of (process, local syncobj d3dkmthandle) pairs
+ * wait for sync file
+ * - get dxgsyncpoint
+ * - if process doesn't have a local syncobj
+ * - create local dxgsyncobject
+ * - send open syncobj to the host
+ * - Send wait for syncobj to the context
+ * dxgsyncpoint destruction
+ * - walk the list of (process, local syncobj)
+ * - destroy syncobj
+ * - remove reference to dxgsharedsyncobject
*/
#include <linux/eventfd.h>
@@ -45,12 +59,15 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
struct d3dkmt_createsyncfile args;
struct dxgsyncpoint *pt = NULL;
int ret = 0;
- int fd = get_unused_fd_flags(O_CLOEXEC);
+ int fd;
struct sync_file *sync_file = NULL;
struct dxgdevice *device = NULL;
struct dxgadapter *adapter = NULL;
+ struct dxgsyncobject *syncobj = NULL;
struct d3dkmt_waitforsynchronizationobjectfromcpu waitargs = {};
+ bool device_lock_acquired = false;
+ fd = get_unused_fd_flags(O_CLOEXEC);
if (fd < 0) {
DXG_ERR("get_unused_fd_flags failed: %d", fd);
ret = fd;
@@ -74,9 +91,9 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
ret = dxgdevice_acquire_lock_shared(device);
if (ret < 0) {
DXG_ERR("dxgdevice_acquire_lock_shared failed");
- device = NULL;
goto cleanup;
}
+ device_lock_acquired = true;
adapter = device->adapter;
ret = dxgadapter_acquire_lock_shared(adapter);
@@ -109,6 +126,30 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
}
dma_fence_put(&pt->base);
+ hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED);
+ syncobj = hmgrtable_get_object(&process->handle_table,
+ args.monitored_fence);
+ if (syncobj == NULL) {
+ DXG_ERR("invalid syncobj handle %x", args.monitored_fence.v);
+ ret = -EINVAL;
+ } else {
+ if (syncobj->shared) {
+ kref_get(&syncobj->syncobj_kref);
+ pt->shared_syncobj = syncobj->shared_owner;
+ }
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED);
+
+ if (pt->shared_syncobj) {
+ ret = dxgsharedsyncobj_get_host_nt_handle(pt->shared_syncobj,
+ process,
+ args.monitored_fence);
+ if (ret)
+ pt->shared_syncobj = NULL;
+ }
+ if (ret)
+ goto cleanup;
+
waitargs.device = args.device;
waitargs.object_count = 1;
waitargs.objects = &args.monitored_fence;
@@ -132,10 +173,15 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
fd_install(fd, sync_file->file);
cleanup:
+ if (syncobj && syncobj->shared)
+ kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
if (adapter)
dxgadapter_release_lock_shared(adapter);
- if (device)
- dxgdevice_release_lock_shared(device);
+ if (device) {
+ if (device_lock_acquired)
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
if (ret) {
if (sync_file) {
fput(sync_file->file);
@@ -151,6 +197,228 @@ int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
return ret;
}
+int dxgkio_open_syncobj_from_syncfile(struct dxgprocess *process,
+ void *__user inargs)
+{
+ struct d3dkmt_opensyncobjectfromsyncfile args;
+ int ret = 0;
+ struct dxgsyncpoint *pt = NULL;
+ struct dma_fence *dmafence = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct dxgsyncobject *syncobj = NULL;
+ struct d3dddi_synchronizationobject_flags flags = { };
+ struct d3dkmt_opensyncobjectfromnthandle2 openargs = { };
+ struct dxgglobal *dxgglobal = dxggbl();
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ dmafence = sync_file_get_fence(args.sync_file_handle);
+ if (dmafence == NULL) {
+ DXG_ERR("failed to get dmafence from handle: %llx",
+ args.sync_file_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ pt = to_syncpoint(dmafence);
+ if (pt->shared_syncobj == NULL) {
+ DXG_ERR("Sync object is not shared");
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ DXG_ERR("dxgprocess_device_by_handle failed");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ DXG_ERR("dxgdevice_acquire_lock_shared failed");
+ kref_put(&device->device_kref, dxgdevice_release);
+ device = NULL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ DXG_ERR("dxgadapter_acquire_lock_shared failed");
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ flags.shared = 1;
+ flags.nt_security_sharing = 1;
+ syncobj = dxgsyncobject_create(process, device, adapter,
+ _D3DDDI_MONITORED_FENCE, flags);
+ if (syncobj == NULL) {
+ DXG_ERR("failed to create sync object");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ dxgsharedsyncobj_add_syncobj(pt->shared_syncobj, syncobj);
+
+ /* Open the shared syncobj to get a local handle */
+
+ openargs.device = device->handle;
+ openargs.flags.shared = 1;
+ openargs.flags.nt_security_sharing = 1;
+ openargs.flags.no_signal = 1;
+
+ ret = dxgvmb_send_open_sync_object_nt(process,
+ &dxgglobal->channel, &openargs, syncobj);
+ if (ret) {
+ DXG_ERR("Failed to open shared syncobj on host");
+ goto cleanup;
+ }
+
+ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+ ret = hmgrtable_assign_handle(&process->handle_table,
+ syncobj,
+ HMGRENTRY_TYPE_DXGSYNCOBJECT,
+ openargs.sync_object);
+ if (ret == 0) {
+ syncobj->handle = openargs.sync_object;
+ kref_get(&syncobj->syncobj_kref);
+ }
+ hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+ args.syncobj = openargs.sync_object;
+ args.fence_value = pt->fence_value;
+ args.fence_value_cpu_va = openargs.monitored_fence.fence_value_cpu_va;
+ args.fence_value_gpu_va = openargs.monitored_fence.fence_value_gpu_va;
+
+ ret = copy_to_user(inargs, &args, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy output args");
+ ret = -EFAULT;
+ }
+
+cleanup:
+ if (dmafence)
+ dma_fence_put(dmafence);
+ if (ret) {
+ if (syncobj) {
+ dxgsyncobject_destroy(process, syncobj);
+ kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
+ }
+ }
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device) {
+ dxgdevice_release_lock_shared(device);
+ kref_put(&device->device_kref, dxgdevice_release);
+ }
+
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ return ret;
+}
+
+int dxgkio_wait_sync_file(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_waitsyncfile args;
+ struct dma_fence *dmafence = NULL;
+ int ret = 0;
+ struct dxgsyncpoint *pt = NULL;
+ struct dxgdevice *device = NULL;
+ struct dxgadapter *adapter = NULL;
+ struct d3dkmthandle syncobj_handle = {};
+ bool device_lock_acquired = false;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ dmafence = sync_file_get_fence(args.sync_file_handle);
+ if (dmafence == NULL) {
+ DXG_ERR("failed to get dmafence from handle: %llx",
+ args.sync_file_handle);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ pt = to_syncpoint(dmafence);
+
+ 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) {
+ DXG_ERR("dxgdevice_acquire_lock_shared failed");
+ device = NULL;
+ goto cleanup;
+ }
+ device_lock_acquired = true;
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ DXG_ERR("dxgadapter_acquire_lock_shared failed");
+ adapter = NULL;
+ goto cleanup;
+ }
+
+ /* Open the shared syncobj to get a local handle */
+ if (pt->shared_syncobj == NULL) {
+ DXG_ERR("Sync object is not shared");
+ goto cleanup;
+ }
+ ret = dxgvmb_send_open_sync_object(process,
+ device->handle,
+ pt->shared_syncobj->host_shared_handle,
+ &syncobj_handle);
+ if (ret) {
+ DXG_ERR("Failed to open shared syncobj on host");
+ goto cleanup;
+ }
+
+ /* Ask the host to insert the syncobj to the context queue */
+ ret = dxgvmb_send_wait_sync_object_gpu(process, adapter,
+ args.context, 1,
+ &syncobj_handle,
+ &pt->fence_value,
+ false);
+ if (ret < 0) {
+ DXG_ERR("dxgvmb_send_wait_sync_object_cpu failed");
+ goto cleanup;
+ }
+
+ /*
+ * Destroy the local syncobject immediately. This will not unblock
+ * GPU waiters, but will unblock CPU waiter, which includes the sync
+ * file itself.
+ */
+ ret = dxgvmb_send_destroy_sync_object(process, syncobj_handle);
+
+cleanup:
+ 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);
+ }
+ if (dmafence)
+ dma_fence_put(dmafence);
+
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ return ret;
+}
+
static const char *dxgdmafence_get_driver_name(struct dma_fence *fence)
{
return "dxgkrnl";
@@ -166,11 +434,16 @@ 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);
- }
+ if (syncpoint == NULL)
+ return;
+
+ if (syncpoint->hdr.event_id)
+ dxgglobal_get_host_event(syncpoint->hdr.event_id);
+
+ if (syncpoint->shared_syncobj)
+ dxgsharedsyncobj_put(syncpoint->shared_syncobj);
+
+ kfree(syncpoint);
}
static bool dxgdmafence_signaled(struct dma_fence *fence)
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.h b/drivers/hv/dxgkrnl/dxgsyncfile.h
index 207ef9b30f67..292b7f718987 100644
--- a/drivers/hv/dxgkrnl/dxgsyncfile.h
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.h
@@ -17,10 +17,13 @@
#include <linux/sync_file.h>
int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs);
+int dxgkio_wait_sync_file(struct dxgprocess *process, void *__user inargs);
+int dxgkio_open_syncobj_from_syncfile(struct dxgprocess *p, void *__user args);
struct dxgsyncpoint {
struct dxghostevent hdr;
struct dma_fence base;
+ struct dxgsharedsyncobject *shared_syncobj;
u64 fence_value;
u64 context;
spinlock_t lock;
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index d53d4254be63..36f4d4e84d3e 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -796,6 +796,55 @@ int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process,
return ret;
}
+int dxgvmb_send_open_sync_object(struct dxgprocess *process,
+ struct d3dkmthandle device,
+ struct d3dkmthandle host_shared_syncobj,
+ struct d3dkmthandle *syncobj)
+{
+ struct dxgkvmb_command_opensyncobject *command;
+ struct dxgkvmb_command_opensyncobject_return result = { };
+ int ret;
+ struct dxgvmbusmsg msg;
+ struct dxgglobal *dxgglobal = dxggbl();
+
+ 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 = device;
+ command->global_sync_object = host_shared_syncobj;
+ command->flags.shared = 1;
+ command->flags.nt_security_sharing = 1;
+ command->flags.no_signal = 1;
+
+ ret = dxgglobal_acquire_channel_lock();
+ if (ret < 0)
+ goto cleanup;
+
+ ret = dxgvmb_send_sync_msg(&dxgglobal->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;
+
+ *syncobj = result.sync_object;
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ DXG_TRACE("err: %d", ret);
+ return ret;
+}
+
int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process,
struct d3dkmthandle object,
struct d3dkmthandle *shared_handle)
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 4db23cd55b24..622904d5c3a9 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -36,10 +36,8 @@ static char *errorstr(int ret)
}
#endif
-static int dxgsyncobj_release(struct inode *inode, struct file *file)
+void dxgsharedsyncobj_put(struct dxgsharedsyncobject *syncobj)
{
- struct dxgsharedsyncobject *syncobj = file->private_data;
-
DXG_TRACE("Release syncobj: %p", syncobj);
mutex_lock(&syncobj->fd_mutex);
kref_get(&syncobj->ssyncobj_kref);
@@ -56,6 +54,13 @@ static int dxgsyncobj_release(struct inode *inode, struct file *file)
}
mutex_unlock(&syncobj->fd_mutex);
kref_put(&syncobj->ssyncobj_kref, dxgsharedsyncobj_release);
+}
+
+static int dxgsyncobj_release(struct inode *inode, struct file *file)
+{
+ struct dxgsharedsyncobject *syncobj = file->private_data;
+
+ dxgsharedsyncobj_put(syncobj);
return 0;
}
@@ -4478,7 +4483,7 @@ dxgkio_get_device_state(struct dxgprocess *process, void *__user inargs)
return ret;
}
-static int
+int
dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj,
struct dxgprocess *process,
struct d3dkmthandle objecthandle)
@@ -5226,6 +5231,9 @@ static struct ioctl_desc ioctls[] = {
/* 0x43 */ {dxgkio_query_statistics, LX_DXQUERYSTATISTICS},
/* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST},
/* 0x45 */ {dxgkio_create_sync_file, LX_DXCREATESYNCFILE},
+/* 0x46 */ {dxgkio_wait_sync_file, LX_DXWAITSYNCFILE},
+/* 0x46 */ {dxgkio_open_syncobj_from_syncfile,
+ LX_DXOPENSYNCOBJECTFROMSYNCFILE},
};
/*
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index c7f168425dc7..1eaa3f038322 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -1561,6 +1561,25 @@ struct d3dkmt_createsyncfile {
__u64 sync_file_handle; /* out */
};
+struct d3dkmt_waitsyncfile {
+ __u64 sync_file_handle;
+ struct d3dkmthandle context;
+ __u32 reserved;
+};
+
+struct d3dkmt_opensyncobjectfromsyncfile {
+ __u64 sync_file_handle;
+ struct d3dkmthandle device;
+ struct d3dkmthandle syncobj; /* out */
+ __u64 fence_value; /* out */
+#ifdef __KERNEL__
+ void *fence_value_cpu_va; /* out */
+#else
+ __u64 fence_value_cpu_va; /* out */
+#endif
+ __u64 fence_value_gpu_va; /* out */
+};
+
/*
* Dxgkrnl Graphics Port Driver ioctl definitions
*
@@ -1686,5 +1705,9 @@ struct d3dkmt_createsyncfile {
_IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost)
#define LX_DXCREATESYNCFILE \
_IOWR(0x47, 0x45, struct d3dkmt_createsyncfile)
+#define LX_DXWAITSYNCFILE \
+ _IOWR(0x47, 0x46, struct d3dkmt_waitsyncfile)
+#define LX_DXOPENSYNCOBJECTFROMSYNCFILE \
+ _IOWR(0x47, 0x47, struct d3dkmt_opensyncobjectfromsyncfile)
#endif /* _D3DKMTHK_H */
^ permalink raw reply related
* [PATCH 32/55] drivers: hv: dxgkrnl: Use tracing instead of dev_dbg
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 4 ++--
drivers/hv/dxgkrnl/dxgmodule.c | 5 ++++-
drivers/hv/dxgkrnl/dxgprocess.c | 6 +++---
drivers/hv/dxgkrnl/dxgvmbus.c | 4 ++--
drivers/hv/dxgkrnl/hmgr.c | 16 ++++++++--------
drivers/hv/dxgkrnl/ioctl.c | 8 ++++----
drivers/hv/dxgkrnl/misc.c | 4 ++--
7 files changed, 25 insertions(+), 22 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index 236febbc6fca..3d8bec295b87 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -18,8 +18,8 @@
#include "dxgkrnl.h"
-#undef pr_fmt
-#define pr_fmt(fmt) "dxgk: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
int dxgadapter_set_vmbus(struct dxgadapter *adapter, struct hv_device *hdev)
{
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index af51fcd35697..08feae97e845 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -24,6 +24,9 @@
#undef pr_fmt
#define pr_fmt(fmt) "dxgk: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
+
/*
* Interface from dxgglobal
*/
@@ -442,7 +445,7 @@ const struct file_operations dxgk_fops = {
#define DXGK_VMBUS_HOSTCAPS_OFFSET (DXGK_VMBUS_VGPU_LUID_OFFSET + \
sizeof(struct winluid))
-/* The guest writes its capavilities to this adderss */
+/* The guest writes its capabilities to this address */
#define DXGK_VMBUS_GUESTCAPS_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
sizeof(u32))
diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgprocess.c
index 5de3f8ccb448..afef196c0588 100644
--- a/drivers/hv/dxgkrnl/dxgprocess.c
+++ b/drivers/hv/dxgkrnl/dxgprocess.c
@@ -13,8 +13,8 @@
#include "dxgkrnl.h"
-#undef pr_fmt
-#define pr_fmt(fmt) "dxgk: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
/*
* Creates a new dxgprocess object
@@ -248,7 +248,7 @@ struct dxgadapter *dxgprocess_adapter_by_handle(struct dxgprocess *process,
HMGRENTRY_TYPE_DXGADAPTER,
handle);
if (adapter == NULL)
- DXG_ERR("adapter_by_handle failed %x", handle.v);
+ DXG_TRACE("adapter_by_handle failed %x", handle.v);
else if (kref_get_unless_zero(&adapter->adapter_kref) == 0) {
DXG_ERR("failed to acquire adapter reference");
adapter = NULL;
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 913ea3cabb31..d53d4254be63 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -22,8 +22,8 @@
#include "dxgkrnl.h"
#include "dxgvmbus.h"
-#undef pr_fmt
-#define pr_fmt(fmt) "dxgk: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
#define RING_BUFSIZE (256 * 1024)
diff --git a/drivers/hv/dxgkrnl/hmgr.c b/drivers/hv/dxgkrnl/hmgr.c
index 526b50f46d96..24101d0091ab 100644
--- a/drivers/hv/dxgkrnl/hmgr.c
+++ b/drivers/hv/dxgkrnl/hmgr.c
@@ -19,8 +19,8 @@
#include "dxgkrnl.h"
#include "hmgr.h"
-#undef pr_fmt
-#define pr_fmt(fmt) "dxgk: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
const struct d3dkmthandle zerohandle;
@@ -90,29 +90,29 @@ static bool is_handle_valid(struct hmgrtable *table, struct d3dkmthandle h,
struct hmgrentry *entry;
if (index >= table->table_size) {
- DXG_ERR("Invalid index %x %d", h.v, index);
+ DXG_TRACE("Invalid index %x %d", h.v, index);
return false;
}
entry = &table->entry_table[index];
if (unique != entry->unique) {
- DXG_ERR("Invalid unique %x %d %d %d %p",
+ DXG_TRACE("Invalid unique %x %d %d %d %p",
h.v, unique, entry->unique, index, entry->object);
return false;
}
if (entry->destroyed && !ignore_destroyed) {
- DXG_ERR("Invalid destroyed value");
+ DXG_TRACE("Invalid destroyed value");
return false;
}
if (entry->type == HMGRENTRY_TYPE_FREE) {
- DXG_ERR("Entry is freed %x %d", h.v, index);
+ DXG_TRACE("Entry is freed %x %d", h.v, index);
return false;
}
if (t != HMGRENTRY_TYPE_FREE && t != entry->type) {
- DXG_ERR("type mismatch %x %d %d", h.v, t, entry->type);
+ DXG_TRACE("type mismatch %x %d %d", h.v, t, entry->type);
return false;
}
@@ -500,7 +500,7 @@ void *hmgrtable_get_object_by_type(struct hmgrtable *table,
struct d3dkmthandle h)
{
if (!is_handle_valid(table, h, false, type)) {
- DXG_ERR("Invalid handle %x", h.v);
+ DXG_TRACE("Invalid handle %x", h.v);
return NULL;
}
return table->entry_table[get_index(h)].object;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 6c26aafb0619..4db23cd55b24 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -21,8 +21,8 @@
#include "dxgvmbus.h"
#include "dxgsyncfile.h"
-#undef pr_fmt
-#define pr_fmt(fmt) "dxgk: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
struct ioctl_desc {
int (*ioctl_callback)(struct dxgprocess *p, void __user *arg);
@@ -556,7 +556,7 @@ dxgkio_enum_adapters3(struct dxgprocess *process, void *__user inargs)
cleanup:
- DXG_TRACE("ioctl: %s %d", errorstr(ret), ret);
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
return ret;
}
@@ -5242,7 +5242,7 @@ static int dxgk_ioctl(struct file *f, unsigned int p1, unsigned long p2)
int status;
struct dxgprocess *process;
- if (code < 1 || code >= ARRAY_SIZE(ioctls)) {
+ if (code < 1 || code >= ARRAY_SIZE(ioctls)) {
DXG_ERR("bad ioctl %x %x %x %x",
code, _IOC_TYPE(p1), _IOC_SIZE(p1), _IOC_DIR(p1));
return -ENOTTY;
diff --git a/drivers/hv/dxgkrnl/misc.c b/drivers/hv/dxgkrnl/misc.c
index 4a1309d80ee5..4bf6fe80d22a 100644
--- a/drivers/hv/dxgkrnl/misc.c
+++ b/drivers/hv/dxgkrnl/misc.c
@@ -18,8 +18,8 @@
#include "dxgkrnl.h"
#include "misc.h"
-#undef pr_fmt
-#define pr_fmt(fmt) "dxgk: " fmt
+#undef dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
u16 *wcsncpy(u16 *dest, const u16 *src, size_t n)
{
^ permalink raw reply related
* [PATCH 31/55] drivers: hv: dxgkrnl: Creation of dxgsyncfile objects
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Implement the ioctl to create a dxgsyncfile object
(LX_DXCREATESYNCFILE). This object is a wrapper around a monitored
fence sync object and a fence value.
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 file descriptor of the sync_file object
is returned to the caller. The caller could wait for the object by using
poll(). When the underlying 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>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/Kconfig | 2 +
drivers/hv/dxgkrnl/Makefile | 2 +-
drivers/hv/dxgkrnl/dxgkrnl.h | 2 +
drivers/hv/dxgkrnl/dxgmodule.c | 12 ++
drivers/hv/dxgkrnl/dxgsyncfile.c | 215 +++++++++++++++++++++++++++++++
drivers/hv/dxgkrnl/dxgsyncfile.h | 30 +++++
drivers/hv/dxgkrnl/dxgvmbus.c | 33 +++--
drivers/hv/dxgkrnl/ioctl.c | 5 +-
include/uapi/misc/d3dkmthk.h | 9 ++
9 files changed, 294 insertions(+), 16 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 bcd92bbff939..782692610887 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 fc85a47a6ad5..89824cda670a 100644
--- a/drivers/hv/dxgkrnl/Makefile
+++ b/drivers/hv/dxgkrnl/Makefile
@@ -2,4 +2,4 @@
# Makefile for the hyper-v compute device driver (dxgkrnl).
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 091dbe999d33..3a69e3b34e1c 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -120,6 +120,7 @@ struct dxgpagingqueue {
*/
enum dxghosteventtype {
dxghostevent_cpu_event = 1,
+ dxghostevent_dma_fence = 2,
};
struct dxghostevent {
@@ -858,6 +859,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 f1245a9d8826..af51fcd35697 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -16,6 +16,7 @@
#include <linux/hyperv.h>
#include <linux/pci.h>
#include "dxgkrnl.h"
+#include "dxgsyncfile.h"
#define PCI_VENDOR_ID_MICROSOFT 0x1414
#define PCI_DEVICE_ID_VIRTUAL_RENDER 0x008E
@@ -145,6 +146,15 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
spin_unlock_irq(&dxgglobal->host_event_list_mutex);
}
+static 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 signal_host_cpu_event(struct dxghostevent *eventhdr)
{
struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
@@ -184,6 +194,8 @@ void dxgglobal_signal_host_event(u64 event_id)
DXG_TRACE("found event to signal");
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
DXG_ERR("Unknown host event type");
break;
diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.c b/drivers/hv/dxgkrnl/dxgsyncfile.c
new file mode 100644
index 000000000000..88fd78f08fbe
--- /dev/null
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2022, 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 dev_fmt
+#define dev_fmt(fmt) "dxgk: " fmt
+
+#ifdef DEBUG
+static char *errorstr(int ret)
+{
+ return ret < 0 ? "err" : "";
+}
+#endif
+
+static const struct dma_fence_ops dxgdmafence_ops;
+
+static struct dxgsyncpoint *to_syncpoint(struct dma_fence *fence)
+{
+ if (fence->ops != &dxgdmafence_ops)
+ return NULL;
+ return container_of(fence, struct dxgsyncpoint, base);
+}
+
+int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inargs)
+{
+ struct d3dkmt_createsyncfile args;
+ struct dxgsyncpoint *pt = NULL;
+ 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) {
+ DXG_ERR("get_unused_fd_flags failed: %d", fd);
+ ret = fd;
+ goto cleanup;
+ }
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ device = dxgprocess_device_by_handle(process, args.device);
+ if (device == NULL) {
+ DXG_ERR("dxgprocess_device_by_handle failed");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgdevice_acquire_lock_shared(device);
+ if (ret < 0) {
+ DXG_ERR("dxgdevice_acquire_lock_shared failed");
+ device = NULL;
+ goto cleanup;
+ }
+
+ adapter = device->adapter;
+ ret = dxgadapter_acquire_lock_shared(adapter);
+ if (ret < 0) {
+ DXG_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) {
+ DXG_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) {
+ DXG_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) {
+ DXG_ERR("failed to copy output args");
+ 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);
+ }
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), 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..207ef9b30f67
--- /dev/null
+++ b/drivers/hv/dxgkrnl/dxgsyncfile.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2022, 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 dxgkio_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 4d7807909284..913ea3cabb31 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -2820,6 +2820,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
struct
d3dkmt_waitforsynchronizationobjectfromcpu
*args,
+ bool user_address,
u64 cpu_event)
{
int ret = -EINVAL;
@@ -2844,19 +2845,25 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process,
command->guest_event_pointer = (u64) cpu_event;
current_pos = (u8 *) &command[1];
- ret = copy_from_user(current_pos, args->objects, object_size);
- if (ret) {
- DXG_ERR("failed to copy objects");
- ret = -EINVAL;
- goto cleanup;
- }
- current_pos += object_size;
- ret = copy_from_user(current_pos, args->fence_values,
- fence_size);
- if (ret) {
- DXG_ERR("failed to copy fences");
- ret = -EINVAL;
- goto cleanup;
+ if (user_address) {
+ ret = copy_from_user(current_pos, args->objects, object_size);
+ if (ret) {
+ DXG_ERR("failed to copy objects");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ current_pos += object_size;
+ ret = copy_from_user(current_pos, args->fence_values,
+ fence_size);
+ if (ret) {
+ DXG_ERR("failed to copy fences");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ } 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/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 8732a66040a0..6c26aafb0619 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: " fmt
@@ -3488,7 +3489,7 @@ dxgkio_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;
@@ -5224,7 +5225,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x42 */ {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE},
/* 0x43 */ {dxgkio_query_statistics, LX_DXQUERYSTATISTICS},
/* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST},
-/* 0x45 */ {},
+/* 0x45 */ {dxgkio_create_sync_file, LX_DXCREATESYNCFILE},
};
/*
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index 1f60f5120e1d..c7f168425dc7 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -1554,6 +1554,13 @@ struct d3dkmt_shareobjectwithhost {
__u64 object_vail_nt_handle;
};
+struct d3dkmt_createsyncfile {
+ struct d3dkmthandle device;
+ struct d3dkmthandle monitored_fence;
+ __u64 fence_value;
+ __u64 sync_file_handle; /* out */
+};
+
/*
* Dxgkrnl Graphics Port Driver ioctl definitions
*
@@ -1677,5 +1684,7 @@ struct d3dkmt_shareobjectwithhost {
_IOWR(0x47, 0x43, struct d3dkmt_querystatistics)
#define LX_DXSHAREOBJECTWITHHOST \
_IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost)
+#define LX_DXCREATESYNCFILE \
+ _IOWR(0x47, 0x45, struct d3dkmt_createsyncfile)
#endif /* _D3DKMTHK_H */
^ permalink raw reply related
* [PATCH 30/55] drivers: hv: dxgkrnl: Remove dxgk_init_ioctls
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
The array of ioctls is initialized statically to remove the unnecessary
function.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgmodule.c | 2 +-
drivers/hv/dxgkrnl/ioctl.c | 15 +++++++--------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index b1b612b90fc1..f1245a9d8826 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -300,7 +300,7 @@ static void dxgglobal_start_adapters(void)
}
/*
- * Stopsthe active dxgadapter objects.
+ * Stop the active dxgadapter objects.
*/
static void dxgglobal_stop_adapters(void)
{
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index f6700e974f25..8732a66040a0 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -26,7 +26,6 @@
struct ioctl_desc {
int (*ioctl_callback)(struct dxgprocess *p, void __user *arg);
u32 ioctl;
- u32 arg_size;
};
#ifdef DEBUG
@@ -91,7 +90,7 @@ static const struct file_operations dxg_resource_fops = {
};
static int dxgkio_open_adapter_from_luid(struct dxgprocess *process,
- void *__user inargs)
+ void *__user inargs)
{
struct d3dkmt_openadapterfromluid args;
int ret;
@@ -1002,7 +1001,7 @@ dxgkio_create_hwqueue(struct dxgprocess *process, void *__user inargs)
}
static int dxgkio_destroy_hwqueue(struct dxgprocess *process,
- void *__user inargs)
+ void *__user inargs)
{
struct d3dkmt_destroyhwqueue args;
int ret;
@@ -2280,7 +2279,8 @@ dxgkio_submit_command(struct dxgprocess *process, void *__user inargs)
}
static int
-dxgkio_submit_command_to_hwqueue(struct dxgprocess *process, void *__user inargs)
+dxgkio_submit_command_to_hwqueue(struct dxgprocess *process,
+ void *__user inargs)
{
int ret;
struct d3dkmt_submitcommandtohwqueue args;
@@ -5087,8 +5087,7 @@ open_resource(struct dxgprocess *process,
}
static int
-dxgkio_open_resource_nt(struct dxgprocess *process,
- void *__user inargs)
+dxgkio_open_resource_nt(struct dxgprocess *process, void *__user inargs)
{
struct d3dkmt_openresourcefromnthandle args;
struct d3dkmt_openresourcefromnthandle *__user args_user = inargs;
@@ -5166,7 +5165,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x14 */ {dxgkio_enum_adapters, LX_DXENUMADAPTERS2},
/* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER},
/* 0x16 */ {dxgkio_change_vidmem_reservation,
- LX_DXCHANGEVIDEOMEMORYRESERVATION},
+ LX_DXCHANGEVIDEOMEMORYRESERVATION},
/* 0x17 */ {},
/* 0x18 */ {dxgkio_create_hwqueue, LX_DXCREATEHWQUEUE},
/* 0x19 */ {dxgkio_destroy_device, LX_DXDESTROYDEVICE},
@@ -5205,7 +5204,7 @@ static struct ioctl_desc ioctls[] = {
LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2},
/* 0x34 */ {dxgkio_submit_command_to_hwqueue, LX_DXSUBMITCOMMANDTOHWQUEUE},
/* 0x35 */ {dxgkio_submit_signal_to_hwqueue,
- LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE},
+ LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE},
/* 0x36 */ {dxgkio_submit_wait_to_hwqueue,
LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE},
/* 0x37 */ {dxgkio_unlock2, LX_DXUNLOCK2},
^ permalink raw reply related
* [PATCH 29/55] drivers: hv: dxgkrnl: Removed struct vmbus_gpadl, which was defined in the main linux branch
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgadapter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index 6f763e326a65..236febbc6fca 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -932,7 +932,7 @@ void dxgallocation_destroy(struct dxgallocation *alloc)
vmbus_teardown_gpadl(dxgglobal_get_vmbus(), &alloc->gpadl);
alloc->gpadl.gpadl_handle = 0;
}
-else
+#else
if (alloc->gpadl) {
DXG_TRACE("Teardown gpadl %d", alloc->gpadl);
vmbus_teardown_gpadl(dxgglobal_get_vmbus(), alloc->gpadl);
^ permalink raw reply related
* [PATCH 28/55] drivers: hv: dxgkrnl: Add support to map guest pages by host
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Implement support for mapping guest memory pages by the host.
This removes hyper-v limitations of using GPADL (guest physical
address list).
Dxgkrnl uses hyper-v GPADLs to share guest system memory with the
host. This method has limitations:
- a single GPADL can represent only ~32MB of memory
- there is a limit of how much memory the total size of GPADLs
in a VM can represent.
To avoid these limitations the host implemented mapping guest memory
pages. Presence of this support is determined by reading PCI config
space. When the support is enabled, dxgkrnl does not use GPADLs and
instead uses the following code flow:
- memory pages of an existing system memory buffer are pinned
- PFNs of the pages are sent to the host via a VM bus message
- the host maps the PFNs to get access to the memory
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/Makefile | 2 +-
drivers/hv/dxgkrnl/dxgkrnl.h | 1 +
drivers/hv/dxgkrnl/dxgmodule.c | 33 +++++++++-
drivers/hv/dxgkrnl/dxgvmbus.c | 117 ++++++++++++++++++++++++---------
drivers/hv/dxgkrnl/dxgvmbus.h | 10 +++
drivers/hv/dxgkrnl/misc.c | 1 +
6 files changed, 129 insertions(+), 35 deletions(-)
diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile
index 9d821e83448a..fc85a47a6ad5 100644
--- a/drivers/hv/dxgkrnl/Makefile
+++ b/drivers/hv/dxgkrnl/Makefile
@@ -2,4 +2,4 @@
# Makefile for the hyper-v compute device driver (dxgkrnl).
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
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 93bc9b41aa41..091dbe999d33 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -316,6 +316,7 @@ struct dxgglobal {
bool misc_registered;
bool pci_registered;
bool vmbus_registered;
+ bool map_guest_pages_enabled;
};
static inline struct dxgglobal *dxggbl(void)
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index 5c364a46b65f..b1b612b90fc1 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -147,7 +147,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) {
@@ -426,7 +426,11 @@ const struct file_operations dxgk_fops = {
#define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
sizeof(u32))
-/* The guest writes its capabilities to this address */
+/* 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))
@@ -441,6 +445,23 @@ 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;
+ };
+};
+
/*
* A helper function to read PCI config space.
*/
@@ -475,6 +496,7 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
struct winluid vgpu_luid = {};
struct dxgk_vmbus_guestcaps guest_caps = {.wsl2 = 1};
struct dxgglobal *dxgglobal = dxggbl();
+ struct dxgk_vmbus_hostcaps host_caps = {};
mutex_lock(&dxgglobal->device_mutex);
@@ -503,6 +525,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/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 425a1ab87bd6..4d7807909284 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -1383,15 +1383,19 @@ 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;
+ struct dxgglobal *dxgglobal = dxggbl();
/*
* Create a guest physical address list and set it as the allocation
@@ -1402,6 +1406,7 @@ int create_existing_sysmem(struct dxgdevice *device,
DXG_TRACE("Alloc size: %lld", alloc_size);
dxgalloc->cpu_address = (void *)sysmem;
+
dxgalloc->pages = vzalloc(npages * sizeof(void *));
if (dxgalloc->pages == NULL) {
DXG_ERR("failed to allocate pages");
@@ -1419,39 +1424,87 @@ int create_existing_sysmem(struct dxgdevice *device,
ret = -ENOMEM;
goto cleanup;
}
- kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
- if (kmem == NULL) {
- DXG_ERR("vmap failed");
- ret = -ENOMEM;
- goto cleanup;
- }
- ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
- alloc_size, &dxgalloc->gpadl);
- if (ret1) {
- DXG_ERR("establish_gpadl failed: %d", ret1);
- ret = -ENOMEM;
- goto cleanup;
- }
+ 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;
+
+ kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
+ if (kmem == NULL) {
+ DXG_ERR("vmap failed");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
+ alloc_size, &dxgalloc->gpadl);
+ if (ret1) {
+ DXG_ERR("establish_gpadl failed: %d", ret1);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
#ifdef _MAIN_KERNEL_
- DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle);
+ DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle);
#else
- DXG_TRACE("New gpadl %d", dxgalloc->gpadl);
+ DXG_TRACE("New gpadl %d", dxgalloc->gpadl);
#endif
- 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;
+ 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;
#ifdef _MAIN_KERNEL_
- set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
+ set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
#else
- set_store_command->gpadl = dxgalloc->gpadl;
+ set_store_command->gpadl = dxgalloc->gpadl;
#endif
- ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
- if (ret < 0)
- DXG_ERR("failed to set existing store: %x", ret);
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
+ msg.size);
+ if (ret < 0)
+ DXG_ERR("failed 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) {
+ DXG_ERR("failed set existing pages: %x", ret);
+ break;
+ }
+ alloc_offset_in_pages += pages_to_send;
+ }
+ }
cleanup:
if (kmem)
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index 88967ff6a505..b4a98f7c2522 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -234,6 +234,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/misc.c b/drivers/hv/dxgkrnl/misc.c
index cb1e0635bebc..4a1309d80ee5 100644
--- a/drivers/hv/dxgkrnl/misc.c
+++ b/drivers/hv/dxgkrnl/misc.c
@@ -35,3 +35,4 @@ u16 *wcsncpy(u16 *dest, const u16 *src, size_t n)
dest[i - 1] = 0;
return dest;
}
+
^ permalink raw reply related
* [PATCH 27/55] drivers: hv: dxgkrnl: Manage compute device virtual addresses
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Implement ioctls to manage compute device virtual addresses (VA):
- LX_DXRESERVEGPUVIRTUALADDRESS,
- LX_DXFREEGPUVIRTUALADDRESS,
- LX_DXMAPGPUVIRTUALADDRESS,
- LX_DXUPDATEGPUVIRTUALADDRESS.
Compute devices access memory by using virtual addressses.
Each process has a dedicated VA space. The video memory manager
on the host is responsible with updating device page tables
before submitting a DMA buffer for execution.
The LX_DXRESERVEGPUVIRTUALADDRESS ioctl reserves a portion of the
process compute device VA space.
The LX_DXMAPGPUVIRTUALADDRESS ioctl reserves a portion of the process
compute device VA space and maps it to the given compute device
allocation.
The LX_DXFREEGPUVIRTUALADDRESS frees the previously reserved portion
of the compute device VA space.
The LX_DXUPDATEGPUVIRTUALADDRESS ioctl adds operations to modify the
compute device VA space to a compute device execution context. It
allows the operations to be queued and synchronized with execution
of other compute device DMA buffers..
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 10 ++
drivers/hv/dxgkrnl/dxgvmbus.c | 150 ++++++++++++++++++++++
drivers/hv/dxgkrnl/dxgvmbus.h | 38 ++++++
drivers/hv/dxgkrnl/ioctl.c | 228 +++++++++++++++++++++++++++++++++-
include/uapi/misc/d3dkmthk.h | 126 +++++++++++++++++++
5 files changed, 548 insertions(+), 4 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 93c3ceb23865..93bc9b41aa41 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -817,6 +817,16 @@ int dxgvmb_send_evict(struct dxgprocess *pr, struct dxgadapter *adapter,
int dxgvmb_send_submit_command(struct dxgprocess *pr,
struct dxgadapter *adapter,
struct d3dkmt_submitcommand *args);
+int dxgvmb_send_map_gpu_va(struct dxgprocess *pr, struct d3dkmthandle h,
+ struct dxgadapter *adapter,
+ struct d3dddi_mapgpuvirtualaddress *args);
+int dxgvmb_send_reserve_gpu_va(struct dxgprocess *pr,
+ struct dxgadapter *adapter,
+ struct d3dddi_reservegpuvirtualaddress *args);
+int dxgvmb_send_free_gpu_va(struct dxgprocess *pr, struct dxgadapter *adapter,
+ struct d3dkmt_freegpuvirtualaddress *args);
+int dxgvmb_send_update_gpu_va(struct dxgprocess *pr, struct dxgadapter *adapter,
+ struct d3dkmt_updategpuvirtualaddress *args);
int dxgvmb_send_create_sync_object(struct dxgprocess *pr,
struct dxgadapter *adapter,
struct d3dkmt_createsynchronizationobject2
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index f4c4a7e7ad8b..425a1ab87bd6 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -2432,6 +2432,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)
+ DXG_TRACE("err: %d", 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)
+ DXG_TRACE("err: %d", 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)
+ DXG_TRACE("err: %d", 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;
+ DXG_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) {
+ DXG_ERR("failed to copy operations");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
+
+cleanup:
+ free_message(&msg, process);
+ if (ret)
+ DXG_TRACE("err: %d", ret);
+ return ret;
+}
+
static void set_result(struct d3dkmt_createsynchronizationobject2 *args,
u64 fence_gpu_va, u8 *va)
{
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index 23f92ab9f8ad..88967ff6a505 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -418,6 +418,44 @@ struct dxgkvmb_command_flushheaptransitions {
struct dxgkvmb_command_vgpu_to_host hdr;
};
+struct dxgkvmb_command_freegpuvirtualaddress {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ struct d3dkmt_freegpuvirtualaddress args;
+};
+
+struct dxgkvmb_command_mapgpuvirtualaddress {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ struct d3dddi_mapgpuvirtualaddress args;
+ struct d3dkmthandle device;
+};
+
+struct dxgkvmb_command_mapgpuvirtualaddress_return {
+ u64 virtual_address;
+ u64 paging_fence_value;
+ struct ntstatus status;
+};
+
+struct dxgkvmb_command_reservegpuvirtualaddress {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ struct d3dddi_reservegpuvirtualaddress args;
+};
+
+struct dxgkvmb_command_reservegpuvirtualaddress_return {
+ u64 virtual_address;
+ u64 paging_fence_value;
+};
+
+struct dxgkvmb_command_updategpuvirtualaddress {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ u64 fence_value;
+ struct d3dkmthandle device;
+ struct d3dkmthandle context;
+ struct d3dkmthandle fence_object;
+ u32 num_operations;
+ u32 flags;
+ struct d3dddi_updategpuvirtualaddress_operation operations[1];
+};
+
struct dxgkvmb_command_queryclockcalibration {
struct dxgkvmb_command_vgpu_to_host hdr;
struct d3dkmt_queryclockcalibration args;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 2700da51bc01..f6700e974f25 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -2492,6 +2492,226 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgkio_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;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ 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)) {
+ DXG_ERR("Unexpected error %x", ret);
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->paging_fence_value,
+ &args.paging_fence_value, sizeof(u64));
+ if (ret2) {
+ DXG_ERR("failed to copy paging fence to user");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->virtual_address, &args.virtual_address,
+ sizeof(args.virtual_address));
+ if (ret2) {
+ DXG_ERR("failed to copy va to user");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ return ret;
+}
+
+static int
+dxgkio_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;
+
+ 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) {
+ device = dxgprocess_device_by_object_handle(process,
+ HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+ args.adapter);
+ if (device == NULL) {
+ DXG_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) {
+ DXG_ERR("failed to copy VA to user");
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (adapter) {
+ dxgadapter_release_lock_shared(adapter);
+ kref_put(&adapter->adapter_kref, dxgadapter_release);
+ }
+
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ return ret;
+}
+
+static int
+dxgkio_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) {
+ 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) {
+ 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
+dxgkio_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) {
+ DXG_ERR("failed to copy input args");
+ 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) {
+ DXG_ERR("failed to copy fence value to user");
+ ret = -EINVAL;
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ return ret;
+}
+
static int
dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs)
{
@@ -4931,11 +5151,11 @@ static struct ioctl_desc ioctls[] = {
/* 0x05 */ {dxgkio_destroy_context, LX_DXDESTROYCONTEXT},
/* 0x06 */ {dxgkio_create_allocation, LX_DXCREATEALLOCATION},
/* 0x07 */ {dxgkio_create_paging_queue, LX_DXCREATEPAGINGQUEUE},
-/* 0x08 */ {},
+/* 0x08 */ {dxgkio_reserve_gpu_va, LX_DXRESERVEGPUVIRTUALADDRESS},
/* 0x09 */ {dxgkio_query_adapter_info, LX_DXQUERYADAPTERINFO},
/* 0x0a */ {dxgkio_query_vidmem_info, LX_DXQUERYVIDEOMEMORYINFO},
/* 0x0b */ {dxgkio_make_resident, LX_DXMAKERESIDENT},
-/* 0x0c */ {},
+/* 0x0c */ {dxgkio_map_gpu_va, LX_DXMAPGPUVIRTUALADDRESS},
/* 0x0d */ {dxgkio_escape, LX_DXESCAPE},
/* 0x0e */ {dxgkio_get_device_state, LX_DXGETDEVICESTATE},
/* 0x0f */ {dxgkio_submit_command, LX_DXSUBMITCOMMAND},
@@ -4956,7 +5176,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x1d */ {dxgkio_destroy_sync_object, LX_DXDESTROYSYNCHRONIZATIONOBJECT},
/* 0x1e */ {dxgkio_evict, LX_DXEVICT},
/* 0x1f */ {dxgkio_flush_heap_transitions, LX_DXFLUSHHEAPTRANSITIONS},
-/* 0x20 */ {},
+/* 0x20 */ {dxgkio_free_gpu_va, LX_DXFREEGPUVIRTUALADDRESS},
/* 0x21 */ {dxgkio_get_context_process_scheduling_priority,
LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY},
/* 0x22 */ {dxgkio_get_context_scheduling_priority,
@@ -4990,7 +5210,7 @@ static struct ioctl_desc ioctls[] = {
LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE},
/* 0x37 */ {dxgkio_unlock2, LX_DXUNLOCK2},
/* 0x38 */ {dxgkio_update_alloc_property, LX_DXUPDATEALLOCPROPERTY},
-/* 0x39 */ {},
+/* 0x39 */ {dxgkio_update_gpu_va, LX_DXUPDATEGPUVIRTUALADDRESS},
/* 0x3a */ {dxgkio_wait_sync_object_cpu,
LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU},
/* 0x3b */ {dxgkio_wait_sync_object_gpu,
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index 944f9d1e73d6..1f60f5120e1d 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -1012,6 +1012,124 @@ struct d3dkmt_evict {
__u64 num_bytes_to_trim;
};
+struct d3dddigpuva_protection_type {
+ union {
+ struct {
+ __u64 write:1;
+ __u64 execute:1;
+ __u64 zero:1;
+ __u64 no_access:1;
+ __u64 system_use_only:1;
+ __u64 reserved:59;
+ };
+ __u64 value;
+ };
+};
+
+enum d3dddi_updategpuvirtualaddress_operation_type {
+ _D3DDDI_UPDATEGPUVIRTUALADDRESS_MAP = 0,
+ _D3DDDI_UPDATEGPUVIRTUALADDRESS_UNMAP = 1,
+ _D3DDDI_UPDATEGPUVIRTUALADDRESS_COPY = 2,
+ _D3DDDI_UPDATEGPUVIRTUALADDRESS_MAP_PROTECT = 3,
+};
+
+struct d3dddi_updategpuvirtualaddress_operation {
+ enum d3dddi_updategpuvirtualaddress_operation_type operation;
+ union {
+ struct {
+ __u64 base_address;
+ __u64 size;
+ struct d3dkmthandle allocation;
+ __u64 allocation_offset;
+ __u64 allocation_size;
+ } map;
+ struct {
+ __u64 base_address;
+ __u64 size;
+ struct d3dkmthandle allocation;
+ __u64 allocation_offset;
+ __u64 allocation_size;
+ struct d3dddigpuva_protection_type protection;
+ __u64 driver_protection;
+ } map_protect;
+ struct {
+ __u64 base_address;
+ __u64 size;
+ struct d3dddigpuva_protection_type protection;
+ } unmap;
+ struct {
+ __u64 source_address;
+ __u64 size;
+ __u64 dest_address;
+ } copy;
+ };
+};
+
+enum d3dddigpuva_reservation_type {
+ _D3DDDIGPUVA_RESERVE_NO_ACCESS = 0,
+ _D3DDDIGPUVA_RESERVE_ZERO = 1,
+ _D3DDDIGPUVA_RESERVE_NO_COMMIT = 2
+};
+
+struct d3dkmt_updategpuvirtualaddress {
+ struct d3dkmthandle device;
+ struct d3dkmthandle context;
+ struct d3dkmthandle fence_object;
+ __u32 num_operations;
+#ifdef __KERNEL__
+ struct d3dddi_updategpuvirtualaddress_operation *operations;
+#else
+ __u64 operations;
+#endif
+ __u32 reserved0;
+ __u32 reserved1;
+ __u64 reserved2;
+ __u64 fence_value;
+ union {
+ struct {
+ __u32 do_not_wait:1;
+ __u32 reserved:31;
+ };
+ __u32 value;
+ } flags;
+ __u32 reserved3;
+};
+
+struct d3dddi_mapgpuvirtualaddress {
+ struct d3dkmthandle paging_queue;
+ __u64 base_address;
+ __u64 minimum_address;
+ __u64 maximum_address;
+ struct d3dkmthandle allocation;
+ __u64 offset_in_pages;
+ __u64 size_in_pages;
+ struct d3dddigpuva_protection_type protection;
+ __u64 driver_protection;
+ __u32 reserved0;
+ __u64 reserved1;
+ __u64 virtual_address;
+ __u64 paging_fence_value;
+};
+
+struct d3dddi_reservegpuvirtualaddress {
+ struct d3dkmthandle adapter;
+ __u64 base_address;
+ __u64 minimum_address;
+ __u64 maximum_address;
+ __u64 size;
+ enum d3dddigpuva_reservation_type reservation_type;
+ __u64 driver_protection;
+ __u64 virtual_address;
+ __u64 paging_fence_value;
+};
+
+struct d3dkmt_freegpuvirtualaddress {
+ struct d3dkmthandle adapter;
+ __u32 reserved;
+ __u64 base_address;
+ __u64 size;
+};
+
enum d3dkmt_memory_segment_group {
_D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL = 0,
_D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL = 1
@@ -1453,12 +1571,16 @@ struct d3dkmt_shareobjectwithhost {
_IOWR(0x47, 0x06, struct d3dkmt_createallocation)
#define LX_DXCREATEPAGINGQUEUE \
_IOWR(0x47, 0x07, struct d3dkmt_createpagingqueue)
+#define LX_DXRESERVEGPUVIRTUALADDRESS \
+ _IOWR(0x47, 0x08, struct d3dddi_reservegpuvirtualaddress)
#define LX_DXQUERYADAPTERINFO \
_IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo)
#define LX_DXQUERYVIDEOMEMORYINFO \
_IOWR(0x47, 0x0a, struct d3dkmt_queryvideomemoryinfo)
#define LX_DXMAKERESIDENT \
_IOWR(0x47, 0x0b, struct d3dddi_makeresident)
+#define LX_DXMAPGPUVIRTUALADDRESS \
+ _IOWR(0x47, 0x0c, struct d3dddi_mapgpuvirtualaddress)
#define LX_DXESCAPE \
_IOWR(0x47, 0x0d, struct d3dkmt_escape)
#define LX_DXGETDEVICESTATE \
@@ -1493,6 +1615,8 @@ struct d3dkmt_shareobjectwithhost {
_IOWR(0x47, 0x1e, struct d3dkmt_evict)
#define LX_DXFLUSHHEAPTRANSITIONS \
_IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions)
+#define LX_DXFREEGPUVIRTUALADDRESS \
+ _IOWR(0x47, 0x20, struct d3dkmt_freegpuvirtualaddress)
#define LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY \
_IOWR(0x47, 0x21, struct d3dkmt_getcontextinprocessschedulingpriority)
#define LX_DXGETCONTEXTSCHEDULINGPRIORITY \
@@ -1529,6 +1653,8 @@ struct d3dkmt_shareobjectwithhost {
_IOWR(0x47, 0x37, struct d3dkmt_unlock2)
#define LX_DXUPDATEALLOCPROPERTY \
_IOWR(0x47, 0x38, struct d3dddi_updateallocproperty)
+#define LX_DXUPDATEGPUVIRTUALADDRESS \
+ _IOWR(0x47, 0x39, struct d3dkmt_updategpuvirtualaddress)
#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU \
_IOWR(0x47, 0x3a, struct d3dkmt_waitforsynchronizationobjectfromcpu)
#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU \
^ permalink raw reply related
* [PATCH 26/55] drivers: hv: dxgkrnl: Manage residency of allocations
From: Eric Curtin @ 2026-03-19 20:24 UTC (permalink / raw)
To: linux-hyperv; +Cc: linux-kernel, iourit, wei.liu, decui, haiyangz
In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com>
From: Iouri Tarassov <iourit@linux.microsoft.com>
Implement ioctls to manage residency of compute device allocations:
- LX_DXMAKERESIDENT,
- LX_DXEVICT.
An allocation is "resident" when the compute devoce is setup to
access it. It means that the allocation is in the local device
memory or in non-pageable system memory.
The current design does not support on demand compute device page
faulting. An allocation must be resident before the compute device
is allowed to access it.
The LX_DXMAKERESIDENT ioctl instructs the video memory manager to
make the given allocations resident. The operation is submitted to
a paging queue (dxgpagingqueue). When the ioctl returns a "pending"
status, a monitored fence sync object can be used to synchronize
with the completion of the operation.
The LX_DXEVICT ioctl istructs the video memory manager to evict
the given allocations from device accessible memory.
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
drivers/hv/dxgkrnl/dxgkrnl.h | 4 +
drivers/hv/dxgkrnl/dxgvmbus.c | 98 +++++++++++++++++++++++
drivers/hv/dxgkrnl/dxgvmbus.h | 27 +++++++
drivers/hv/dxgkrnl/ioctl.c | 141 +++++++++++++++++++++++++++++++++-
include/uapi/misc/d3dkmthk.h | 54 +++++++++++++
5 files changed, 322 insertions(+), 2 deletions(-)
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index 02d10bdcc820..93c3ceb23865 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -810,6 +810,10 @@ int dxgvmb_send_create_allocation(struct dxgprocess *pr, struct dxgdevice *dev,
int dxgvmb_send_destroy_allocation(struct dxgprocess *pr, struct dxgdevice *dev,
struct d3dkmt_destroyallocation2 *args,
struct d3dkmthandle *alloc_handles);
+int dxgvmb_send_make_resident(struct dxgprocess *pr, struct dxgadapter *adapter,
+ struct d3dddi_makeresident *args);
+int dxgvmb_send_evict(struct dxgprocess *pr, struct dxgadapter *adapter,
+ struct d3dkmt_evict *args);
int dxgvmb_send_submit_command(struct dxgprocess *pr,
struct dxgadapter *adapter,
struct d3dkmt_submitcommand *args);
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 9a610d48bed7..f4c4a7e7ad8b 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -2279,6 +2279,104 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
return ret;
}
+int dxgvmb_send_make_resident(struct dxgprocess *process,
+ struct dxgadapter *adapter,
+ struct d3dddi_makeresident *args)
+{
+ int ret;
+ u32 cmd_size;
+ 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) {
+ DXG_ERR("failed to copy alloc handles");
+ 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) {
+ DXG_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)
+ DXG_TRACE("err: %d", 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) {
+ DXG_ERR("failed to copy alloc handles");
+ 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) {
+ DXG_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)
+ DXG_TRACE("err: %d", ret);
+ return ret;
+}
+
int dxgvmb_send_submit_command(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_submitcommand *args)
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index 509482e1f870..23f92ab9f8ad 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -372,6 +372,33 @@ struct dxgkvmb_command_flushdevice {
enum dxgdevice_flushschedulerreason reason;
};
+struct dxgkvmb_command_makeresident {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ struct d3dkmthandle device;
+ struct d3dkmthandle paging_queue;
+ struct d3dddi_makeresident_flags flags;
+ u32 alloc_count;
+ struct d3dkmthandle allocations[1];
+};
+
+struct dxgkvmb_command_makeresident_return {
+ u64 paging_fence_value;
+ u64 num_bytes_to_trim;
+ struct ntstatus status;
+};
+
+struct dxgkvmb_command_evict {
+ struct dxgkvmb_command_vgpu_to_host hdr;
+ struct d3dkmthandle device;
+ struct d3dddi_evict_flags flags;
+ u32 alloc_count;
+ struct d3dkmthandle allocations[1];
+};
+
+struct dxgkvmb_command_evict_return {
+ u64 num_bytes_to_trim;
+};
+
struct dxgkvmb_command_submitcommand {
struct dxgkvmb_command_vgpu_to_host hdr;
struct d3dkmt_submitcommand args;
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index bc0adebe52ae..2700da51bc01 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -1961,6 +1961,143 @@ dxgkio_destroy_allocation(struct dxgprocess *process, void *__user inargs)
return ret;
}
+static int
+dxgkio_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;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.alloc_count > D3DKMT_MAKERESIDENT_ALLOC_MAX ||
+ args.alloc_count == 0) {
+ DXG_ERR("invalid number of allocations");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ if (args.paging_queue.v == 0) {
+ DXG_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)) {
+ DXG_ERR("Unexpected error %x", ret);
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->paging_fence_value,
+ &args.paging_fence_value, sizeof(u64));
+ if (ret2) {
+ DXG_ERR("failed to copy paging fence");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ret2 = copy_to_user(&input->num_bytes_to_trim,
+ &args.num_bytes_to_trim, sizeof(u64));
+ if (ret2) {
+ DXG_ERR("failed to copy bytes to trim");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+
+ return ret;
+}
+
+static int
+dxgkio_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;
+
+ ret = copy_from_user(&args, inargs, sizeof(args));
+ if (ret) {
+ DXG_ERR("failed to copy input args");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if (args.alloc_count > D3DKMT_MAKERESIDENT_ALLOC_MAX ||
+ args.alloc_count == 0) {
+ DXG_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) {
+ DXG_ERR("failed to copy bytes to trim to user");
+ ret = -EINVAL;
+ }
+cleanup:
+
+ if (adapter)
+ dxgadapter_release_lock_shared(adapter);
+ if (device)
+ kref_put(&device->device_kref, dxgdevice_release);
+
+ DXG_TRACE("ioctl:%s %d", errorstr(ret), ret);
+ return ret;
+}
+
static int
dxgkio_offer_allocations(struct dxgprocess *process, void *__user inargs)
{
@@ -4797,7 +4934,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x08 */ {},
/* 0x09 */ {dxgkio_query_adapter_info, LX_DXQUERYADAPTERINFO},
/* 0x0a */ {dxgkio_query_vidmem_info, LX_DXQUERYVIDEOMEMORYINFO},
-/* 0x0b */ {},
+/* 0x0b */ {dxgkio_make_resident, LX_DXMAKERESIDENT},
/* 0x0c */ {},
/* 0x0d */ {dxgkio_escape, LX_DXESCAPE},
/* 0x0e */ {dxgkio_get_device_state, LX_DXGETDEVICESTATE},
@@ -4817,7 +4954,7 @@ static struct ioctl_desc ioctls[] = {
/* 0x1b */ {dxgkio_destroy_hwqueue, LX_DXDESTROYHWQUEUE},
/* 0x1c */ {dxgkio_destroy_paging_queue, LX_DXDESTROYPAGINGQUEUE},
/* 0x1d */ {dxgkio_destroy_sync_object, LX_DXDESTROYSYNCHRONIZATIONOBJECT},
-/* 0x1e */ {},
+/* 0x1e */ {dxgkio_evict, LX_DXEVICT},
/* 0x1f */ {dxgkio_flush_heap_transitions, LX_DXFLUSHHEAPTRANSITIONS},
/* 0x20 */ {},
/* 0x21 */ {dxgkio_get_context_process_scheduling_priority,
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index a9bafab97c18..944f9d1e73d6 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -962,6 +962,56 @@ struct d3dkmt_destroyallocation2 {
struct d3dddicb_destroyallocation2flags flags;
};
+struct d3dddi_makeresident_flags {
+ union {
+ struct {
+ __u32 cant_trim_further:1;
+ __u32 must_succeed:1;
+ __u32 reserved:30;
+ };
+ __u32 value;
+ };
+};
+
+struct d3dddi_makeresident {
+ struct d3dkmthandle paging_queue;
+ __u32 alloc_count;
+#ifdef __KERNEL__
+ const struct d3dkmthandle *allocation_list;
+ const __u32 *priority_list;
+#else
+ __u64 allocation_list;
+ __u64 priority_list;
+#endif
+ struct d3dddi_makeresident_flags flags;
+ __u64 paging_fence_value;
+ __u64 num_bytes_to_trim;
+};
+
+struct d3dddi_evict_flags {
+ union {
+ struct {
+ __u32 evict_only_if_necessary:1;
+ __u32 not_written_to:1;
+ __u32 reserved:30;
+ };
+ __u32 value;
+ };
+};
+
+struct d3dkmt_evict {
+ struct d3dkmthandle device;
+ __u32 alloc_count;
+#ifdef __KERNEL__
+ const struct d3dkmthandle *allocations;
+#else
+ __u64 allocations;
+#endif
+ struct d3dddi_evict_flags flags;
+ __u32 reserved;
+ __u64 num_bytes_to_trim;
+};
+
enum d3dkmt_memory_segment_group {
_D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL = 0,
_D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL = 1
@@ -1407,6 +1457,8 @@ struct d3dkmt_shareobjectwithhost {
_IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo)
#define LX_DXQUERYVIDEOMEMORYINFO \
_IOWR(0x47, 0x0a, struct d3dkmt_queryvideomemoryinfo)
+#define LX_DXMAKERESIDENT \
+ _IOWR(0x47, 0x0b, struct d3dddi_makeresident)
#define LX_DXESCAPE \
_IOWR(0x47, 0x0d, struct d3dkmt_escape)
#define LX_DXGETDEVICESTATE \
@@ -1437,6 +1489,8 @@ struct d3dkmt_shareobjectwithhost {
_IOWR(0x47, 0x19, struct d3dkmt_destroydevice)
#define LX_DXDESTROYSYNCHRONIZATIONOBJECT \
_IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject)
+#define LX_DXEVICT \
+ _IOWR(0x47, 0x1e, struct d3dkmt_evict)
#define LX_DXFLUSHHEAPTRANSITIONS \
_IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions)
#define LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY \
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox