From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE9383A63F6 for ; Thu, 19 Mar 2026 20:25:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951918; cv=none; b=kmsnqR5fg/yyl1UTfixna+19/Cf06bLeVx93ZJDsTbdIGqEnM5LLWGGtDk/CEf1TWeno+ScJg73rXqlnE8tEr21pSRoocxAJ1VE4/WNiFprMekS5Odaca/dzVMK2UWt+YhVxzgMm9+9iBNJ5ngLEUxe7y7brdz8ub/GIs4nAVdc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951918; c=relaxed/simple; bh=guTsrnrhj+z/8raDwwr03ZX487NMzNKDJOkO2xeLXtg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X780SMXydDoXg5pRHDQIchEBE6IRZfj3qn+wl0AspA20KIpKtbP7vV4jDM/XxlaiObOQyDhjb7doyWi1pXxzfGPCoyefEitrLN3extzjabD0qDsCPbUP9lFhlNOb9mUayXhXmuP9UZSqVULG1wlyWGh60Ap/u+In8LCbyhHqSOI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=PTF/lU3+; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PTF/lU3+" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-486fda2a389so4679925e9.1 for ; Thu, 19 Mar 2026 13:25:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951914; x=1774556714; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FgaBnxVGpKVzavghfacsVWKIZiZMLKpPl85sTCUs9Bw=; b=PTF/lU3+3Cv62gG+dRyooy+sdhCLzyfs3jTHysUIAfekwD6/6HFOyWdXXF3VQqn361 BkTYJyR8gRN0Q5zl9QItJ2jKVur6VybBS/v1lz4oup0qqyFGvHeQ1pkEM+zWDevos31C lxsFh8j+KTFVElvRu1MMbJ+numFW27eWN76YaVJqh5YlmVQDLc7bQMDeTfXD4PWthUe9 zYp7Ucq8o+hv09073Gn5b4+tLMHuUBIqi2HSJ3uHxI9pAm/M2y5LxShI0HVmCUl8g47+ /lt4oQ1W6d5QUI2bXzguE4ignzyNu7nIzYDZ5PdDYGeYORapdedEHnQ0RrCtiB0dUuwi Knwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951914; x=1774556714; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=FgaBnxVGpKVzavghfacsVWKIZiZMLKpPl85sTCUs9Bw=; b=UGl3+/jPjbU3QoJfKll6xl4zqLLRpkv5JmnJ8TaWeFNlgt6sRhn+frOIL9IkmfIsqS 7KX3EzwR+KNuR5BlMnmzCLJ0v9SLJ9bLxSF1YUNLQnm2bbOc1pmcDGZMXJcjukI9rb+C XcWnQVdKo6GWT/3gLvP1T6wX2uxbJUjSJeYBZ/3ve57mPxdveiYDVb+RSmxA0r3pwZBd ncAtM88/R5PKjyLKymjdW15KRCV6zHgYupvonEr3egzXzp2+oTrJcETo4beRG1GtsVaP Bnt7IR+/y07MW/J+cCev/7rvryrRVdh928cQVkJ43Ijokc1lPTiNP8KaBRhy+3fxej0P S3SQ== X-Gm-Message-State: AOJu0Yz/L3mwlhsGS4OIwqM8lyJmqEfs0HrXj92dDs7d1hYnKjllP+bH C0ukZv35xrgKXgk7m6JTNkYW+f94sT+NZsBeF68BnGsXTTRrQrhELo68 X-Gm-Gg: ATEYQzwJdqImxijgc/2BaaKwDh4ajscCtwt2SGG9P+/pJybKPBwM6Cdr0ZTcD6DqcFw 7pcUkg5ZXxkRj7BXQsPTpq4z+QwTVFXKjciMc6nPq4+L6MVNN8qLWSc5nefQVVaYLxH3+Hj9m1g WFG18xqRJhpiGpYo4yuKz4WzWyfi7a9AHc3AcWd1t4fMkglupif9XPy+FrOffwmFcame+iZECzC 1ObkZwEnrw3+qKH9x2Cnnxgb1p5A5zNPNuGF6Qgsg0IJhYa77CaDko0dYE211GV02JsMirBcb4d UfUzC3KYPihOLqX5b1WnusIj6ATX8vH9srwn6HpYsGgzTIrv3Ii9WK1G+XP1Zl9LEfcDTiZsXRp H613HTmxqTfD3QR1tyXCufArdk+7WctWcg6wJ57i+sJiz3t5rknNjfGC8a2H3AoKIslY/8A+5pL j+Uz3NeWPJUR5IJRuBc4Q0tilEPJG4hgTqwZScZ6HZUXVQ5Mcj X-Received: by 2002:a05:600c:828d:b0:47e:e48b:506d with SMTP id 5b1f17b1804b1-486ff0291ccmr7166145e9.16.1773951913713; Thu, 19 Mar 2026 13:25:13 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.12 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:13 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 01/55] drivers: hv: dxgkrnl: Driver initialization and loading Date: Thu, 19 Mar 2026 20:24:15 +0000 Message-ID: <20260319202509.63802-2-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov - Create skeleton and add basic functionality for the Hyper-V compute device driver (dxgkrnl). - Register for PCI and VMBus driver notifications and handle initialization of VMBus channels. - Connect the dxgkrnl module to the drivers/hv/ Makefile and Kconfig - Create a MAINTAINERS entry A VMBus channel is a communication interface between the Hyper-V guest and the host. The are two type of VMBus channels, used in the driver: - the global channel - per virtual compute device channel A PCI device is created for each virtual compute device, projected by the host. The device vendor is PCI_VENDOR_ID_MICROSOFT and device id is PCI_DEVICE_ID_VIRTUAL_RENDER. dxg_pci_probe_device handles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VMBus channels. VMBus interface version is exchanged by reading/writing the PCI config space of the virtual compute device. The IO space is used to handle CPU accessible compute device allocations. Hyper-V allocates IO space for the global VMBus channel. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- MAINTAINERS | 7 + drivers/hv/Kconfig | 2 + drivers/hv/Makefile | 1 + drivers/hv/dxgkrnl/Kconfig | 26 ++ drivers/hv/dxgkrnl/Makefile | 5 + drivers/hv/dxgkrnl/dxgkrnl.h | 155 ++++++++++ drivers/hv/dxgkrnl/dxgmodule.c | 506 +++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.c | 92 ++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 19 ++ include/uapi/misc/d3dkmthk.h | 27 ++ 10 files changed, 840 insertions(+) create mode 100644 drivers/hv/dxgkrnl/Kconfig create mode 100644 drivers/hv/dxgkrnl/Makefile create mode 100644 drivers/hv/dxgkrnl/dxgkrnl.h create mode 100644 drivers/hv/dxgkrnl/dxgmodule.c create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.c create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.h create mode 100644 include/uapi/misc/d3dkmthk.h diff --git a/MAINTAINERS b/MAINTAINERS index ae4c0cec5073..4fe0b3501931 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9771,6 +9771,13 @@ F: Documentation/devicetree/bindings/mtd/ti,am654-hb= mc.yaml F: drivers/mtd/hyperbus/ F: include/linux/mtd/hyperbus.h =20 +Hyper-V vGPU DRIVER +M: Iouri Tarassov +L: linux-hyperv@vger.kernel.org +S: Supported +F: drivers/hv/dxgkrnl/ +F: include/uapi/misc/d3dkmthk.h + HYPERVISOR VIRTUAL CONSOLE DRIVER L: linuxppc-dev@lists.ozlabs.org S: Odd Fixes diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 862c47b191af..b16c7701da19 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -55,4 +55,6 @@ config HYPERV_BALLOON help Select this option to enable Hyper-V Balloon driver. =20 +source "drivers/hv/dxgkrnl/Kconfig" + endmenu diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile index d76df5c8c2a9..aa1cbdb5d0d2 100644 --- a/drivers/hv/Makefile +++ b/drivers/hv/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_HYPERV) +=3D hv_vmbus.o obj-$(CONFIG_HYPERV_UTILS) +=3D hv_utils.o obj-$(CONFIG_HYPERV_BALLOON) +=3D hv_balloon.o +obj-$(CONFIG_DXGKRNL) +=3D dxgkrnl/ =20 CFLAGS_hv_trace.o =3D -I$(src) CFLAGS_hv_balloon.o =3D -I$(src) diff --git a/drivers/hv/dxgkrnl/Kconfig b/drivers/hv/dxgkrnl/Kconfig new file mode 100644 index 000000000000..bcd92bbff939 --- /dev/null +++ b/drivers/hv/dxgkrnl/Kconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0 +# Configuration for the hyper-v virtual compute driver (dxgkrnl) +# + +config DXGKRNL + tristate "Microsoft Paravirtualized GPU support" + depends on HYPERV + depends on 64BIT || COMPILE_TEST + help + This driver supports paravirtualized virtual compute devices, exposed + by Microsoft Hyper-V when Linux is running inside of a virtual machine + hosted by Windows. The virtual machines needs to be configured to use + host compute adapters. The driver name is dxgkrnl. + + An example of such virtual machine is a Windows Subsystem for + Linux container. When such container is instantiated, the Windows host + assigns compatible host GPU adapters to the container. The corresponding + virtual GPU devices appear on the PCI bus in the container. These + devices are enumerated and accessed by this driver. + + Communications with the driver are done by using the Microsoft libdxcore + library, which translates the D3DKMT interface + + to the driver IOCTLs. The virtual GPU devices are paravirtualized, + which means that access to the hardware is done in the host. The driver + communicates with the host using Hyper-V VM bus communication channels. diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile new file mode 100644 index 000000000000..76349064b60a --- /dev/null +++ b/drivers/hv/dxgkrnl/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for the hyper-v compute device driver (dxgkrnl). + +obj-$(CONFIG_DXGKRNL) +=3D dxgkrnl.o +dxgkrnl-y :=3D dxgmodule.o dxgvmbus.o diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h new file mode 100644 index 000000000000..f7900840d1ed --- /dev/null +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Headers for internal objects + * + */ + +#ifndef _DXGKRNL_H +#define _DXGKRNL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct dxgadapter; + +/* + * Driver private data. + * A single /dev/dxg device is created per virtual machine. + */ +struct dxgdriver{ + struct dxgglobal *dxgglobal; + struct device *dxgdev; + struct pci_driver pci_drv; + struct hv_driver vmbus_drv; +}; +extern struct dxgdriver dxgdrv; + +#define DXGDEV dxgdrv.dxgdev + +struct dxgvmbuschannel { + struct vmbus_channel *channel; + struct hv_device *hdev; + spinlock_t packet_list_mutex; + struct list_head packet_list_head; + struct kmem_cache *packet_cache; + atomic64_t packet_request_id; +}; + +int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hde= v); +void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch); +void dxgvmbuschannel_receive(void *ctx); + +/* + * The structure defines an offered vGPU vm bus channel. + */ +struct dxgvgpuchannel { + struct list_head vgpu_ch_list_entry; + struct winluid adapter_luid; + struct hv_device *hdev; +}; + +struct dxgglobal { + struct dxgdriver *drvdata; + struct dxgvmbuschannel channel; + struct hv_device *hdev; + u32 num_adapters; + u32 vmbus_ver; /* Interface version */ + struct resource *mem; + u64 mmiospace_base; + u64 mmiospace_size; + struct miscdevice dxgdevice; + struct mutex device_mutex; + + /* + * List of the vGPU VM bus channels (dxgvgpuchannel) + * Protected by device_mutex + */ + struct list_head vgpu_ch_list_head; + + /* protects acces to the global VM bus channel */ + struct rw_semaphore channel_lock; + + bool global_channel_initialized; + bool async_msg_enabled; + bool misc_registered; + bool pci_registered; + bool vmbus_registered; +}; + +static inline struct dxgglobal *dxggbl(void) +{ + return dxgdrv.dxgglobal; +} + +struct dxgprocess { + /* Placeholder */ +}; + +/* + * The convention is that VNBus instance id is a GUID, but the host sets + * the lower part of the value to the host adapter LUID. The function + * provides the necessary conversion. + */ +static inline void guid_to_luid(guid_t *guid, struct winluid *luid) +{ + *luid =3D *(struct winluid *)&guid->b[0]; +} + +/* + * VM bus interface + * + */ + +/* + * The interface version is used to ensure that the host and the guest use= the + * same VM bus protocol. It needs to be incremented every time the VM bus + * interface changes. DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION is + * incremented each time the earlier versions of the interface are no long= er + * compatible with the current version. + */ +#define DXGK_VMBUS_INTERFACE_VERSION_OLD 27 +#define DXGK_VMBUS_INTERFACE_VERSION 40 +#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16 + +#ifdef DEBUG + +void dxgk_validate_ioctls(void); + +#define DXG_TRACE(fmt, ...) do { \ + 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__); \ +} while (0) + +#else + +#define DXG_TRACE(...) +#define DXG_ERR(fmt, ...) do { \ + dev_err(DXGDEV, fmt, ##__VA_ARGS__); \ +} while (0) + +#endif /* DEBUG */ + +#endif diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c new file mode 100644 index 000000000000..de02edc4d023 --- /dev/null +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Interface with Linux kernel, PCI driver and the VM bus driver + * + */ + +#include +#include +#include +#include +#include "dxgkrnl.h" + +#define PCI_VENDOR_ID_MICROSOFT 0x1414 +#define PCI_DEVICE_ID_VIRTUAL_RENDER 0x008E + +#undef pr_fmt +#define pr_fmt(fmt) "dxgk: " fmt + +/* + * Interface from dxgglobal + */ + +struct vmbus_channel *dxgglobal_get_vmbus(void) +{ + return dxggbl()->channel.channel; +} + +struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel(void) +{ + return &dxggbl()->channel; +} + +int dxgglobal_acquire_channel_lock(void) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + down_read(&dxgglobal->channel_lock); + if (dxgglobal->channel.channel =3D=3D NULL) { + DXG_ERR("Failed to acquire global channel lock"); + return -ENODEV; + } else { + return 0; + } +} + +void dxgglobal_release_channel_lock(void) +{ + up_read(&dxggbl()->channel_lock); +} + +const struct file_operations dxgk_fops =3D { + .owner =3D THIS_MODULE, +}; + +/* + * Interface with the PCI driver + */ + +/* + * Part of the PCI config space of the compute device is used for + * configuration data. Reading/writing of the PCI config space is forwarded + * to the host. + * + * Below are offsets in the PCI config spaces for various configuration va= lues. + */ + +/* Compute device VM bus channel instance ID */ +#define DXGK_VMBUS_CHANNEL_ID_OFFSET 192 + +/* DXGK_VMBUS_INTERFACE_VERSION (u32) */ +#define DXGK_VMBUS_VERSION_OFFSET (DXGK_VMBUS_CHANNEL_ID_OFFSET + \ + sizeof(guid_t)) + +/* Luid of the virtual GPU on the host (struct winluid) */ +#define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \ + sizeof(u32)) + +/* The guest writes its capabilities to this address */ +#define DXGK_VMBUS_GUESTCAPS_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \ + sizeof(u32)) + +/* Capabilities of the guest driver, reported to the host */ +struct dxgk_vmbus_guestcaps { + union { + struct { + u32 wsl2 : 1; + u32 reserved : 31; + }; + u32 guest_caps; + }; +}; + +/* + * A helper function to read PCI config space. + */ +static int dxg_pci_read_dwords(struct pci_dev *dev, int offset, int size, + void *val) +{ + int off =3D offset; + int ret; + int i; + + /* Make sure the offset and size are 32 bit aligned */ + if (offset & 3 || size & 3) + return -EINVAL; + + for (i =3D 0; i < size / sizeof(int); i++) { + ret =3D pci_read_config_dword(dev, off, &((int *)val)[i]); + if (ret) { + DXG_ERR("Failed to read PCI config: %d", off); + return ret; + } + off +=3D sizeof(int); + } + return 0; +} + +static int dxg_pci_probe_device(struct pci_dev *dev, + const struct pci_device_id *id) +{ + int ret; + guid_t guid; + u32 vmbus_interface_ver =3D DXGK_VMBUS_INTERFACE_VERSION; + struct winluid vgpu_luid =3D {}; + struct dxgk_vmbus_guestcaps guest_caps =3D {.wsl2 =3D 1}; + struct dxgglobal *dxgglobal =3D dxggbl(); + + mutex_lock(&dxgglobal->device_mutex); + + if (dxgglobal->vmbus_ver =3D=3D 0) { + /* Report capabilities to the host */ + + ret =3D pci_write_config_dword(dev, DXGK_VMBUS_GUESTCAPS_OFFSET, + guest_caps.guest_caps); + if (ret) + goto cleanup; + + /* Negotiate the VM bus version */ + + ret =3D pci_read_config_dword(dev, DXGK_VMBUS_VERSION_OFFSET, + &vmbus_interface_ver); + if (ret =3D=3D 0 && vmbus_interface_ver !=3D 0) + dxgglobal->vmbus_ver =3D vmbus_interface_ver; + else + dxgglobal->vmbus_ver =3D DXGK_VMBUS_INTERFACE_VERSION_OLD; + + if (dxgglobal->vmbus_ver < DXGK_VMBUS_INTERFACE_VERSION) + goto read_channel_id; + + ret =3D pci_write_config_dword(dev, DXGK_VMBUS_VERSION_OFFSET, + DXGK_VMBUS_INTERFACE_VERSION); + if (ret) + goto cleanup; + + if (dxgglobal->vmbus_ver > DXGK_VMBUS_INTERFACE_VERSION) + dxgglobal->vmbus_ver =3D DXGK_VMBUS_INTERFACE_VERSION; + } + +read_channel_id: + + /* Get the VM bus channel ID for the virtual GPU */ + ret =3D dxg_pci_read_dwords(dev, DXGK_VMBUS_CHANNEL_ID_OFFSET, + sizeof(guid), (int *)&guid); + if (ret) + goto cleanup; + + if (dxgglobal->vmbus_ver >=3D DXGK_VMBUS_INTERFACE_VERSION) { + ret =3D dxg_pci_read_dwords(dev, DXGK_VMBUS_VGPU_LUID_OFFSET, + sizeof(vgpu_luid), &vgpu_luid); + if (ret) + goto cleanup; + } + + DXG_TRACE("Adapter channel: %pUb", &guid); + DXG_TRACE("Vmbus interface version: %d", dxgglobal->vmbus_ver); + DXG_TRACE("Host luid: %x-%x", vgpu_luid.b, vgpu_luid.a); + +cleanup: + + mutex_unlock(&dxgglobal->device_mutex); + + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +static void dxg_pci_remove_device(struct pci_dev *dev) +{ + /* Placeholder */ +} + +static struct pci_device_id dxg_pci_id_table[] =3D { + { + .vendor =3D PCI_VENDOR_ID_MICROSOFT, + .device =3D PCI_DEVICE_ID_VIRTUAL_RENDER, + .subvendor =3D PCI_ANY_ID, + .subdevice =3D PCI_ANY_ID + }, + { 0 } +}; + +/* + * Interface with the VM bus driver + */ + +static int dxgglobal_getiospace(struct dxgglobal *dxgglobal) +{ + /* Get mmio space for the global channel */ + struct hv_device *hdev =3D dxgglobal->hdev; + struct vmbus_channel *channel =3D hdev->channel; + resource_size_t pot_start =3D 0; + resource_size_t pot_end =3D -1; + int ret; + + dxgglobal->mmiospace_size =3D channel->offermsg.offer.mmio_megabytes; + if (dxgglobal->mmiospace_size =3D=3D 0) { + DXG_TRACE("Zero mmio space is offered"); + return -ENOMEM; + } + dxgglobal->mmiospace_size <<=3D 20; + DXG_TRACE("mmio offered: %llx", dxgglobal->mmiospace_size); + + ret =3D vmbus_allocate_mmio(&dxgglobal->mem, hdev, pot_start, pot_end, + dxgglobal->mmiospace_size, 0x10000, false); + if (ret) { + DXG_ERR("Unable to allocate mmio memory: %d", ret); + return ret; + } + dxgglobal->mmiospace_size =3D dxgglobal->mem->end - + dxgglobal->mem->start + 1; + dxgglobal->mmiospace_base =3D dxgglobal->mem->start; + DXG_TRACE("mmio allocated %llx %llx %llx %llx", + dxgglobal->mmiospace_base, dxgglobal->mmiospace_size, + dxgglobal->mem->start, dxgglobal->mem->end); + + return 0; +} + +int dxgglobal_init_global_channel(void) +{ + int ret =3D 0; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D dxgvmbuschannel_init(&dxgglobal->channel, dxgglobal->hdev); + if (ret) { + DXG_ERR("dxgvmbuschannel_init failed: %d", ret); + goto error; + } + + ret =3D dxgglobal_getiospace(dxgglobal); + if (ret) { + DXG_ERR("getiospace failed: %d", ret); + goto error; + } + + hv_set_drvdata(dxgglobal->hdev, dxgglobal); + +error: + return ret; +} + +void dxgglobal_destroy_global_channel(void) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + down_write(&dxgglobal->channel_lock); + + dxgglobal->global_channel_initialized =3D false; + + if (dxgglobal->mem) { + vmbus_free_mmio(dxgglobal->mmiospace_base, + dxgglobal->mmiospace_size); + dxgglobal->mem =3D NULL; + } + + dxgvmbuschannel_destroy(&dxgglobal->channel); + + if (dxgglobal->hdev) { + hv_set_drvdata(dxgglobal->hdev, NULL); + dxgglobal->hdev =3D NULL; + } + + up_write(&dxgglobal->channel_lock); +} + +static const struct hv_vmbus_device_id dxg_vmbus_id_table[] =3D { + /* Per GPU Device GUID */ + { HV_GPUP_DXGK_VGPU_GUID }, + /* Global Dxgkgnl channel for the virtual machine */ + { HV_GPUP_DXGK_GLOBAL_GUID }, + { } +}; + +static int dxg_probe_vmbus(struct hv_device *hdev, + const struct hv_vmbus_device_id *dev_id) +{ + int ret =3D 0; + struct winluid luid; + struct dxgvgpuchannel *vgpuch; + struct dxgglobal *dxgglobal =3D dxggbl(); + + mutex_lock(&dxgglobal->device_mutex); + + if (uuid_le_cmp(hdev->dev_type, dxg_vmbus_id_table[0].guid) =3D=3D 0) { + /* This is a new virtual GPU channel */ + guid_to_luid(&hdev->channel->offermsg.offer.if_instance, &luid); + DXG_TRACE("vGPU channel: %pUb", + &hdev->channel->offermsg.offer.if_instance); + vgpuch =3D kzalloc(sizeof(struct dxgvgpuchannel), GFP_KERNEL); + if (vgpuch =3D=3D NULL) { + ret =3D -ENOMEM; + goto error; + } + vgpuch->adapter_luid =3D luid; + vgpuch->hdev =3D hdev; + list_add_tail(&vgpuch->vgpu_ch_list_entry, + &dxgglobal->vgpu_ch_list_head); + } else if (uuid_le_cmp(hdev->dev_type, + dxg_vmbus_id_table[1].guid) =3D=3D 0) { + /* This is the global Dxgkgnl channel */ + DXG_TRACE("Global channel: %pUb", + &hdev->channel->offermsg.offer.if_instance); + if (dxgglobal->hdev) { + /* This device should appear only once */ + DXG_ERR("global channel already exists"); + ret =3D -EBADE; + goto error; + } + dxgglobal->hdev =3D hdev; + } else { + /* Unknown device type */ + DXG_ERR("Unknown VM bus device type"); + ret =3D -ENODEV; + } + +error: + + mutex_unlock(&dxgglobal->device_mutex); + + return ret; +} + +static int dxg_remove_vmbus(struct hv_device *hdev) +{ + int ret =3D 0; + struct dxgvgpuchannel *vgpu_channel; + struct dxgglobal *dxgglobal =3D dxggbl(); + + mutex_lock(&dxgglobal->device_mutex); + + if (uuid_le_cmp(hdev->dev_type, dxg_vmbus_id_table[0].guid) =3D=3D 0) { + DXG_TRACE("Remove virtual GPU channel"); + list_for_each_entry(vgpu_channel, + &dxgglobal->vgpu_ch_list_head, + vgpu_ch_list_entry) { + if (vgpu_channel->hdev =3D=3D hdev) { + list_del(&vgpu_channel->vgpu_ch_list_entry); + kfree(vgpu_channel); + break; + } + } + } else if (uuid_le_cmp(hdev->dev_type, + dxg_vmbus_id_table[1].guid) =3D=3D 0) { + DXG_TRACE("Remove global channel device"); + dxgglobal_destroy_global_channel(); + } else { + /* Unknown device type */ + DXG_ERR("Unknown device type"); + ret =3D -ENODEV; + } + + mutex_unlock(&dxgglobal->device_mutex); + + return ret; +} + +MODULE_DEVICE_TABLE(vmbus, dxg_vmbus_id_table); +MODULE_DEVICE_TABLE(pci, dxg_pci_id_table); + +/* + * Global driver data + */ + +struct dxgdriver dxgdrv =3D { + .vmbus_drv.name =3D KBUILD_MODNAME, + .vmbus_drv.id_table =3D dxg_vmbus_id_table, + .vmbus_drv.probe =3D dxg_probe_vmbus, + .vmbus_drv.remove =3D dxg_remove_vmbus, + .vmbus_drv.driver =3D { + .probe_type =3D PROBE_PREFER_ASYNCHRONOUS, + }, + .pci_drv.name =3D KBUILD_MODNAME, + .pci_drv.id_table =3D dxg_pci_id_table, + .pci_drv.probe =3D dxg_pci_probe_device, + .pci_drv.remove =3D dxg_pci_remove_device +}; + +static struct dxgglobal *dxgglobal_create(void) +{ + struct dxgglobal *dxgglobal; + + dxgglobal =3D kzalloc(sizeof(struct dxgglobal), GFP_KERNEL); + if (!dxgglobal) + return NULL; + + mutex_init(&dxgglobal->device_mutex); + + INIT_LIST_HEAD(&dxgglobal->vgpu_ch_list_head); + + init_rwsem(&dxgglobal->channel_lock); + + return dxgglobal; +} + +static void dxgglobal_destroy(struct dxgglobal *dxgglobal) +{ + if (dxgglobal) { + mutex_lock(&dxgglobal->device_mutex); + dxgglobal_destroy_global_channel(); + mutex_unlock(&dxgglobal->device_mutex); + + if (dxgglobal->vmbus_registered) + vmbus_driver_unregister(&dxgdrv.vmbus_drv); + + dxgglobal_destroy_global_channel(); + + if (dxgglobal->pci_registered) + pci_unregister_driver(&dxgdrv.pci_drv); + + if (dxgglobal->misc_registered) + misc_deregister(&dxgglobal->dxgdevice); + + dxgglobal->drvdata->dxgdev =3D NULL; + + kfree(dxgglobal); + dxgglobal =3D NULL; + } +} + +static int __init dxg_drv_init(void) +{ + int ret; + struct dxgglobal *dxgglobal =3D NULL; + + dxgglobal =3D dxgglobal_create(); + if (dxgglobal =3D=3D NULL) { + pr_err("dxgglobal_init failed"); + ret =3D -ENOMEM; + goto error; + } + dxgglobal->drvdata =3D &dxgdrv; + + dxgglobal->dxgdevice.minor =3D MISC_DYNAMIC_MINOR; + dxgglobal->dxgdevice.name =3D "dxg"; + dxgglobal->dxgdevice.fops =3D &dxgk_fops; + dxgglobal->dxgdevice.mode =3D 0666; + ret =3D misc_register(&dxgglobal->dxgdevice); + if (ret) { + pr_err("misc_register failed: %d", ret); + goto error; + } + dxgglobal->misc_registered =3D true; + dxgdrv.dxgdev =3D dxgglobal->dxgdevice.this_device; + dxgdrv.dxgglobal =3D dxgglobal; + + ret =3D vmbus_driver_register(&dxgdrv.vmbus_drv); + if (ret) { + DXG_ERR("vmbus_driver_register failed: %d", ret); + goto error; + } + dxgglobal->vmbus_registered =3D true; + + ret =3D pci_register_driver(&dxgdrv.pci_drv); + if (ret) { + DXG_ERR("pci_driver_register failed: %d", ret); + goto error; + } + dxgglobal->pci_registered =3D true; + + return 0; + +error: + /* This function does the cleanup */ + dxgglobal_destroy(dxgglobal); + dxgdrv.dxgglobal =3D NULL; + + return ret; +} + +static void __exit dxg_drv_exit(void) +{ + dxgglobal_destroy(dxgdrv.dxgglobal); +} + +module_init(dxg_drv_init); +module_exit(dxg_drv_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Microsoft Dxgkrnl virtual compute device Driver"); diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c new file mode 100644 index 000000000000..deb880e34377 --- /dev/null +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * VM bus interface implementation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dxgkrnl.h" +#include "dxgvmbus.h" + +#undef pr_fmt +#define pr_fmt(fmt) "dxgk: " fmt + +#define RING_BUFSIZE (256 * 1024) + +/* + * The structure is used to track VM bus packets, waiting for completion. + */ +struct dxgvmbuspacket { + struct list_head packet_list_entry; + u64 request_id; + struct completion wait; + void *buffer; + u32 buffer_length; + int status; + bool completed; +}; + +int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hde= v) +{ + int ret; + + ch->hdev =3D hdev; + spin_lock_init(&ch->packet_list_mutex); + INIT_LIST_HEAD(&ch->packet_list_head); + atomic64_set(&ch->packet_request_id, 0); + + ch->packet_cache =3D kmem_cache_create("DXGK packet cache", + sizeof(struct dxgvmbuspacket), 0, + 0, NULL); + if (ch->packet_cache =3D=3D NULL) { + DXG_ERR("packet_cache alloc failed"); + ret =3D -ENOMEM; + goto cleanup; + } + +#if LINUX_VERSION_CODE >=3D KERNEL_VERSION(5,15,0) + hdev->channel->max_pkt_size =3D DXG_MAX_VM_BUS_PACKET_SIZE; +#endif + ret =3D vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE, + NULL, 0, dxgvmbuschannel_receive, ch); + if (ret) { + DXG_ERR("vmbus_open failed: %d", ret); + goto cleanup; + } + + ch->channel =3D hdev->channel; + +cleanup: + + return ret; +} + +void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch) +{ + kmem_cache_destroy(ch->packet_cache); + ch->packet_cache =3D NULL; + + if (ch->channel) { + vmbus_close(ch->channel); + ch->channel =3D NULL; + } +} + +/* Receive callback for messages from the host */ +void dxgvmbuschannel_receive(void *ctx) +{ +} diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h new file mode 100644 index 000000000000..6cdca5e03d1f --- /dev/null +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * VM bus interface with the host definitions + * + */ + +#ifndef _DXGVMBUS_H +#define _DXGVMBUS_H + +#define DXG_MAX_VM_BUS_PACKET_SIZE (1024 * 128) + +#endif /* _DXGVMBUS_H */ diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h new file mode 100644 index 000000000000..5d973604400c --- /dev/null +++ b/include/uapi/misc/d3dkmthk.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +/* + * Copyright (c) 2019, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * User mode WDDM interface definitions + * + */ + +#ifndef _D3DKMTHK_H +#define _D3DKMTHK_H + +/* + * Matches the Windows LUID definition. + * LUID is a locally unique identifier (similar to GUID, but not global), + * which is guaranteed to be unique intil the computer is rebooted. + */ +struct winluid { + __u32 a; + __u32 b; +}; + +#endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B65133F7E7F for ; Thu, 19 Mar 2026 20:25:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951918; cv=none; b=o8ZxrBM19ghyIFqrC8jTepsIGWAnE/Gjs4KuPRQfEXnIY+Ht2azb2wHj1wapuKjflUgHNxKLBzHwoEcfGiJYHFMQZbyBgHuEOx/93HbtK3KAPWiJw6Vo2aW1scAJTAuy3VoIBKMswhlBRM9/2kM5pKjMIMUbSqPKnILbGk2NgOE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951918; c=relaxed/simple; bh=rf9C9hNgxWx2kMLhpGO21VXiqOAsEUYHcjwCPuzzl9Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nsE3DaEmsK2BE4S5ldQBuRM/kKC7B+RPtCutFqptTdvECLdvREQzlxFP3bj3I0vbp61ie0XUpf1KC73f5XLhlR12ROeOfA+MgqG7xYZ5ZFSCnw2yE7DvJLlTkNH8DyWZadVue8f9i/Qn478YFCE6I/GwXVx3AefffQqoKoZXtEc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=byoJb4WK; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="byoJb4WK" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-48538c5956bso12088995e9.0 for ; Thu, 19 Mar 2026 13:25:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951915; x=1774556715; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=3xJZuo2ZZgXft86owpVORMUXvi8FA22p3zGYoG+woB0=; b=byoJb4WKtfk8ZgAU33EqlQQggPRuC6luZAVBDneWQSwlNgpgkb0FS+Q3u0JQ643aI1 DsNq/pADGxwp+fPSErtW0nASuFTxB5CRa4mmBb+hstfULqhxKJbIEhdnH5aeCMofXfmS Qv6dYjHXygijn0CSLrcqiskZ4lqknslhiWcEl0yUGajGIPshx3Ef7NGGxu+cNDSU2Key 4+Z0Pb0pHYVRvaYmgP5rxf0rd3f2s2QJoZ7wgWtf6Ni3cdB6XxGHy+SkikWXc7jkOIlp H1gbRZabjmUlf945zYr2HqEkATCVPCZ/eN8LAtR+hPW7DBGYTqh3JL7VQj46Pcs4f9ev aCbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951915; x=1774556715; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=3xJZuo2ZZgXft86owpVORMUXvi8FA22p3zGYoG+woB0=; b=pJp0++9Vs+J7ax3Xgu8p1gkJxyVw9wuIdtPi5LJSu0rVBu3H5hwRenAOA6QI5070ur 8Sa/iOKKrlY4+An+h1mMuSqFNIZWhZ26O0KoNcqRyVOLMKHPdHjcc8/VrBDqKKHEUFka u6XQ56V951hVcI6QoOB14LNps9a/bNj3FHrbEDX6LX8R0W1JaHDPzGTs9bK/I+poWaMx 5bEmXFDbOAb+feBHJdRo5UFiHtM13w+S4i5tzEGoTt8oKClhHbKej/CZbtlDOKnS33dq eXTEo5j+6qlY8jM+xyWFXBKLUnEVwkxRs7EDTPDxxta18LugQ0sUbSOEkuJq++YzTfkC d6dg== X-Gm-Message-State: AOJu0YzmyzVgmYwRs7O4JTpkYB9z9aLJ0Z+7umX2B0dMPCuZlqMcV7HN zsH/t1jirfKiSSbWq++zMLoMHFOEtYASk7VeOtAJjJfRWrSVK3WSMZEb X-Gm-Gg: ATEYQzyHgpe42HetS/CAYuErd3XzCx0az+VmAF6gkG+JYDK1H1TK3HB4efFJn5j1s4D LEpGV31DPqW6LRtVBRt9wnBVhkNusmdyYC19MSd+8d6D6Bx4x3JpmvRefCHgoVuq0Fb9krNSo9g t0hrQ5xKYZw45OjX+i2YAarN9kEfOeS/oQEBXi+1ENeic6rT08nGKp9Q0MqhQtatys/P41jrprc b7JQpEWvab7IZvch89qk9UfM8glatBUVhnCWkKGnLochKTHrpkN8BOio/qaGIXS929YO2MwAOUk HoVxme3oc9C8E1EMUh/Q4gX7Lt5g3rdeAQGVrWDK8x6TOHCzOnNsGwQ4oF3c57pjTIFmcZmVm3e kfFwZI+KHzR0O++ZadDn1nBUXGFQyaiCpkXDuo06JOTibxxk/XPh3pJ0ybehWTWUPFaG3/Ei9BL OGpFV+bIuN+wrv5oOxa5oSXFQpShAZg6h1QCLXHh972AgXbn7A X-Received: by 2002:a05:600c:3e10:b0:485:3428:774c with SMTP id 5b1f17b1804b1-486fe8b0073mr11988675e9.4.1773951914869; Thu, 19 Mar 2026 13:25:14 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.13 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:14 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 02/55] drivers: hv: dxgkrnl: Add VMBus message support, initialize VMBus channels. Date: Thu, 19 Mar 2026 20:24:16 +0000 Message-ID: <20260319202509.63802-3-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement support for sending/receiving VMBus messages between the host and the guest. Initialize the VMBus channels and notify the host about IO space settings of the VMBus global channel. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 14 ++ drivers/hv/dxgkrnl/dxgmodule.c | 9 +- drivers/hv/dxgkrnl/dxgvmbus.c | 318 +++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 67 +++++++ drivers/hv/dxgkrnl/ioctl.c | 24 +++ drivers/hv/dxgkrnl/misc.h | 72 ++++++++ include/uapi/misc/d3dkmthk.h | 34 ++++ 7 files changed, 536 insertions(+), 2 deletions(-) create mode 100644 drivers/hv/dxgkrnl/ioctl.c create mode 100644 drivers/hv/dxgkrnl/misc.h diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index f7900840d1ed..52b9e82c51e6 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -28,6 +28,8 @@ #include #include #include +#include "misc.h" +#include =20 struct dxgadapter; =20 @@ -100,6 +102,13 @@ static inline struct dxgglobal *dxggbl(void) return dxgdrv.dxgglobal; } =20 +int dxgglobal_init_global_channel(void); +void dxgglobal_destroy_global_channel(void); +struct vmbus_channel *dxgglobal_get_vmbus(void); +struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel(void); +int dxgglobal_acquire_channel_lock(void); +void dxgglobal_release_channel_lock(void); + struct dxgprocess { /* Placeholder */ }; @@ -130,6 +139,11 @@ static inline void guid_to_luid(guid_t *guid, struct w= inluid *luid) #define DXGK_VMBUS_INTERFACE_VERSION 40 #define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16 =20 +void dxgvmb_initialize(void); +int dxgvmb_send_set_iospace_region(u64 start, u64 len); + +int ntstatus2int(struct ntstatus status); + #ifdef DEBUG =20 void dxgk_validate_ioctls(void); diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index de02edc4d023..e55639dc0adc 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -260,6 +260,13 @@ int dxgglobal_init_global_channel(void) goto error; } =20 + ret =3D dxgvmb_send_set_iospace_region(dxgglobal->mmiospace_base, + dxgglobal->mmiospace_size); + if (ret < 0) { + DXG_ERR("send_set_iospace_region failed"); + goto error; + } + hv_set_drvdata(dxgglobal->hdev, dxgglobal); =20 error: @@ -429,8 +436,6 @@ static void dxgglobal_destroy(struct dxgglobal *dxgglob= al) if (dxgglobal->vmbus_registered) vmbus_driver_unregister(&dxgdrv.vmbus_drv); =20 - dxgglobal_destroy_global_channel(); - if (dxgglobal->pci_registered) pci_unregister_driver(&dxgdrv.pci_drv); =20 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index deb880e34377..a4365739826a 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -40,6 +40,121 @@ struct dxgvmbuspacket { bool completed; }; =20 +struct dxgvmb_ext_header { + /* Offset from the start of the message to DXGKVMB_COMMAND_BASE */ + u32 command_offset; + u32 reserved; + struct winluid vgpu_luid; +}; + +#define VMBUSMESSAGEONSTACK 64 + +struct dxgvmbusmsg { +/* Points to the allocated buffer */ + struct dxgvmb_ext_header *hdr; +/* Points to dxgkvmb_command_vm_to_host or dxgkvmb_command_vgpu_to_host */ + void *msg; +/* The vm bus channel, used to pass the message to the host */ + struct dxgvmbuschannel *channel; +/* Message size in bytes including the header and the payload */ + u32 size; +/* Buffer used for small messages */ + char msg_on_stack[VMBUSMESSAGEONSTACK]; +}; + +struct dxgvmbusmsgres { +/* Points to the allocated buffer */ + struct dxgvmb_ext_header *hdr; +/* Points to dxgkvmb_command_vm_to_host or dxgkvmb_command_vgpu_to_host */ + void *msg; +/* The vm bus channel, used to pass the message to the host */ + struct dxgvmbuschannel *channel; +/* Message size in bytes including the header, the payload and the result = */ + u32 size; +/* Result buffer size in bytes */ + u32 res_size; +/* Points to the result within the allocated buffer */ + void *res; +}; + +static int init_message(struct dxgvmbusmsg *msg, + struct dxgprocess *process, u32 size) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + bool use_ext_header =3D dxgglobal->vmbus_ver >=3D + DXGK_VMBUS_INTERFACE_VERSION; + + if (use_ext_header) + size +=3D sizeof(struct dxgvmb_ext_header); + msg->size =3D size; + if (size <=3D VMBUSMESSAGEONSTACK) { + msg->hdr =3D (void *)msg->msg_on_stack; + memset(msg->hdr, 0, size); + } else { + msg->hdr =3D vzalloc(size); + if (msg->hdr =3D=3D NULL) + return -ENOMEM; + } + if (use_ext_header) { + msg->msg =3D (char *)&msg->hdr[1]; + msg->hdr->command_offset =3D sizeof(msg->hdr[0]); + } else { + msg->msg =3D (char *)msg->hdr; + } + msg->channel =3D &dxgglobal->channel; + return 0; +} + +static void free_message(struct dxgvmbusmsg *msg, struct dxgprocess *proce= ss) +{ + if (msg->hdr && (char *)msg->hdr !=3D msg->msg_on_stack) + vfree(msg->hdr); +} + +/* + * Helper functions + */ + +int ntstatus2int(struct ntstatus status) +{ + if (NT_SUCCESS(status)) + return (int)status.v; + switch (status.v) { + case STATUS_OBJECT_NAME_COLLISION: + return -EEXIST; + case STATUS_NO_MEMORY: + return -ENOMEM; + case STATUS_INVALID_PARAMETER: + return -EINVAL; + case STATUS_OBJECT_NAME_INVALID: + case STATUS_OBJECT_NAME_NOT_FOUND: + return -ENOENT; + case STATUS_TIMEOUT: + return -EAGAIN; + case STATUS_BUFFER_TOO_SMALL: + return -EOVERFLOW; + case STATUS_DEVICE_REMOVED: + return -ENODEV; + case STATUS_ACCESS_DENIED: + return -EACCES; + case STATUS_NOT_SUPPORTED: + return -EPERM; + case STATUS_ILLEGAL_INSTRUCTION: + return -EOPNOTSUPP; + case STATUS_INVALID_HANDLE: + return -EBADF; + case STATUS_GRAPHICS_ALLOCATION_BUSY: + return -EINPROGRESS; + case STATUS_OBJECT_TYPE_MISMATCH: + return -EPROTOTYPE; + case STATUS_NOT_IMPLEMENTED: + return -EPERM; + default: + return -EINVAL; + } +} + int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hde= v) { int ret; @@ -86,7 +201,210 @@ void dxgvmbuschannel_destroy(struct dxgvmbuschannel *c= h) } } =20 +static void command_vm_to_host_init1(struct dxgkvmb_command_vm_to_host *co= mmand, + enum dxgkvmb_commandtype_global type) +{ + command->command_type =3D type; + command->process.v =3D 0; + command->command_id =3D 0; + command->channel_type =3D DXGKVMB_VM_TO_HOST; +} + +static void process_inband_packet(struct dxgvmbuschannel *channel, + struct vmpacket_descriptor *desc) +{ + u32 packet_length =3D hv_pkt_datalen(desc); + struct dxgkvmb_command_host_to_vm *packet; + + if (packet_length < sizeof(struct dxgkvmb_command_host_to_vm)) { + DXG_ERR("Invalid global packet"); + } else { + packet =3D hv_pkt_data(desc); + DXG_TRACE("global packet %d", + packet->command_type); + switch (packet->command_type) { + case DXGK_VMBCOMMAND_SIGNALGUESTEVENT: + case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE: + break; + case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION: + break; + default: + DXG_ERR("unexpected host message %d", + packet->command_type); + } + } +} + +static void process_completion_packet(struct dxgvmbuschannel *channel, + struct vmpacket_descriptor *desc) +{ + struct dxgvmbuspacket *packet =3D NULL; + struct dxgvmbuspacket *entry; + u32 packet_length =3D hv_pkt_datalen(desc); + unsigned long flags; + + spin_lock_irqsave(&channel->packet_list_mutex, flags); + list_for_each_entry(entry, &channel->packet_list_head, + packet_list_entry) { + if (desc->trans_id =3D=3D entry->request_id) { + packet =3D entry; + list_del(&packet->packet_list_entry); + packet->completed =3D true; + break; + } + } + spin_unlock_irqrestore(&channel->packet_list_mutex, flags); + if (packet) { + if (packet->buffer_length) { + if (packet_length < packet->buffer_length) { + DXG_TRACE("invalid size %d Expected:%d", + packet_length, + packet->buffer_length); + packet->status =3D -EOVERFLOW; + } else { + memcpy(packet->buffer, hv_pkt_data(desc), + packet->buffer_length); + } + } + complete(&packet->wait); + } else { + DXG_ERR("did not find packet to complete"); + } +} + /* Receive callback for messages from the host */ void dxgvmbuschannel_receive(void *ctx) { + struct dxgvmbuschannel *channel =3D ctx; + struct vmpacket_descriptor *desc; + u32 packet_length =3D 0; + + foreach_vmbus_pkt(desc, channel->channel) { + packet_length =3D hv_pkt_datalen(desc); + DXG_TRACE("next packet (id, size, type): %llu %d %d", + desc->trans_id, packet_length, desc->type); + if (desc->type =3D=3D VM_PKT_COMP) { + process_completion_packet(channel, desc); + } else { + if (desc->type !=3D VM_PKT_DATA_INBAND) + DXG_ERR("unexpected packet type"); + else + process_inband_packet(channel, desc); + } + } +} + +int dxgvmb_send_sync_msg(struct dxgvmbuschannel *channel, + void *command, + u32 cmd_size, + void *result, + u32 result_size) +{ + int ret; + struct dxgvmbuspacket *packet =3D NULL; + + if (cmd_size > DXG_MAX_VM_BUS_PACKET_SIZE || + result_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("%s invalid data size", __func__); + return -EINVAL; + } + + packet =3D kmem_cache_alloc(channel->packet_cache, 0); + if (packet =3D=3D NULL) { + DXG_ERR("kmem_cache_alloc failed"); + return -ENOMEM; + } + + packet->request_id =3D atomic64_inc_return(&channel->packet_request_id); + init_completion(&packet->wait); + packet->buffer =3D result; + packet->buffer_length =3D result_size; + packet->status =3D 0; + packet->completed =3D false; + spin_lock_irq(&channel->packet_list_mutex); + list_add_tail(&packet->packet_list_entry, &channel->packet_list_head); + spin_unlock_irq(&channel->packet_list_mutex); + + ret =3D vmbus_sendpacket(channel->channel, command, cmd_size, + packet->request_id, VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret) { + DXG_ERR("vmbus_sendpacket failed: %x", ret); + spin_lock_irq(&channel->packet_list_mutex); + list_del(&packet->packet_list_entry); + spin_unlock_irq(&channel->packet_list_mutex); + goto cleanup; + } + + DXG_TRACE("waiting completion: %llu", packet->request_id); + ret =3D wait_for_completion_killable(&packet->wait); + if (ret) { + DXG_ERR("wait_for_completion failed: %x", ret); + spin_lock_irq(&channel->packet_list_mutex); + if (!packet->completed) + list_del(&packet->packet_list_entry); + spin_unlock_irq(&channel->packet_list_mutex); + goto cleanup; + } + DXG_TRACE("completion done: %llu %x", + packet->request_id, packet->status); + ret =3D packet->status; + +cleanup: + + kmem_cache_free(channel->packet_cache, packet); + if (ret < 0) + DXG_TRACE("Error: %x", ret); + return ret; +} + +static int +dxgvmb_send_sync_msg_ntstatus(struct dxgvmbuschannel *channel, + void *command, u32 cmd_size) +{ + struct ntstatus status; + int ret; + + ret =3D dxgvmb_send_sync_msg(channel, command, cmd_size, + &status, sizeof(status)); + if (ret >=3D 0) + ret =3D ntstatus2int(status); + return ret; +} + +/* + * Global messages to the host + */ + +int dxgvmb_send_set_iospace_region(u64 start, u64 len) +{ + int ret; + struct dxgkvmb_command_setiospaceregion *command; + struct dxgvmbusmsg msg; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D init_message(&msg, NULL, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + command_vm_to_host_init1(&command->hdr, + DXGK_VMBCOMMAND_SETIOSPACEREGION); + command->start =3D start; + command->length =3D len; + ret =3D dxgvmb_send_sync_msg_ntstatus(&dxgglobal->channel, msg.hdr, + msg.size); + if (ret < 0) + DXG_ERR("send_set_iospace_region failed %x", ret); + + dxgglobal_release_channel_lock(); +cleanup: + free_message(&msg, NULL); + if (ret) + DXG_TRACE("Error: %d", ret); + return ret; } diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 6cdca5e03d1f..b1bdd6039b73 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -16,4 +16,71 @@ =20 #define DXG_MAX_VM_BUS_PACKET_SIZE (1024 * 128) =20 +enum dxgkvmb_commandchanneltype { + DXGKVMB_VGPU_TO_HOST, + DXGKVMB_VM_TO_HOST, + DXGKVMB_HOST_TO_VM +}; + +/* + * + * Commands, sent to the host via the guest global VM bus channel + * DXG_GUEST_GLOBAL_VMBUS + * + */ + +enum dxgkvmb_commandtype_global { + DXGK_VMBCOMMAND_VM_TO_HOST_FIRST =3D 1000, + DXGK_VMBCOMMAND_CREATEPROCESS =3D DXGK_VMBCOMMAND_VM_TO_HOST_FIRST, + DXGK_VMBCOMMAND_DESTROYPROCESS =3D 1001, + DXGK_VMBCOMMAND_OPENSYNCOBJECT =3D 1002, + DXGK_VMBCOMMAND_DESTROYSYNCOBJECT =3D 1003, + DXGK_VMBCOMMAND_CREATENTSHAREDOBJECT =3D 1004, + DXGK_VMBCOMMAND_DESTROYNTSHAREDOBJECT =3D 1005, + DXGK_VMBCOMMAND_SIGNALFENCE =3D 1006, + DXGK_VMBCOMMAND_NOTIFYPROCESSFREEZE =3D 1007, + DXGK_VMBCOMMAND_NOTIFYPROCESSTHAW =3D 1008, + DXGK_VMBCOMMAND_QUERYETWSESSION =3D 1009, + DXGK_VMBCOMMAND_SETIOSPACEREGION =3D 1010, + DXGK_VMBCOMMAND_COMPLETETRANSACTION =3D 1011, + DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST =3D 1021, + DXGK_VMBCOMMAND_INVALID_VM_TO_HOST +}; + +/* + * Commands, sent by the host to the VM + */ +enum dxgkvmb_commandtype_host_to_vm { + DXGK_VMBCOMMAND_SIGNALGUESTEVENT, + DXGK_VMBCOMMAND_PROPAGATEPRESENTHISTORYTOKEN, + DXGK_VMBCOMMAND_SETGUESTDATA, + DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE, + DXGK_VMBCOMMAND_SENDWNFNOTIFICATION, + DXGK_VMBCOMMAND_INVALID_HOST_TO_VM +}; + +struct dxgkvmb_command_vm_to_host { + u64 command_id; + struct d3dkmthandle process; + enum dxgkvmb_commandchanneltype channel_type; + enum dxgkvmb_commandtype_global command_type; +}; + +struct dxgkvmb_command_host_to_vm { + u64 command_id; + struct d3dkmthandle process; + u32 channel_type : 8; + u32 async_msg : 1; + u32 reserved : 23; + enum dxgkvmb_commandtype_host_to_vm command_type; +}; + +/* Returns ntstatus */ +struct dxgkvmb_command_setiospaceregion { + struct dxgkvmb_command_vm_to_host hdr; + u64 start; + u64 length; + u32 shared_page_gpadl; +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c new file mode 100644 index 000000000000..23ecd15b0cd7 --- /dev/null +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Ioctl implementation + * + */ + +#include +#include +#include +#include +#include + +#include "dxgkrnl.h" +#include "dxgvmbus.h" + +#undef pr_fmt +#define pr_fmt(fmt) "dxgk: " fmt diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h new file mode 100644 index 000000000000..4c6047c32a20 --- /dev/null +++ b/drivers/hv/dxgkrnl/misc.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Misc definitions + * + */ + +#ifndef _MISC_H_ +#define _MISC_H_ + +extern const struct d3dkmthandle zerohandle; + +/* + * Synchronization lock hierarchy. + * + * The higher enum value, the higher is the lock order. + * When a lower lock ois held, the higher lock should not be acquired. + * + * channel_lock + * device_mutex + */ + +/* + * Some of the Windows return codes, which needs to be translated to Linux + * IOCTL return codes. Positive values are success codes and need to be + * returned from the driver IOCTLs. libdxcore.so depends on returning + * specific return codes. + */ +#define STATUS_SUCCESS ((int)(0)) +#define STATUS_OBJECT_NAME_INVALID ((int)(0xC0000033L)) +#define STATUS_DEVICE_REMOVED ((int)(0xC00002B6L)) +#define STATUS_INVALID_HANDLE ((int)(0xC0000008L)) +#define STATUS_ILLEGAL_INSTRUCTION ((int)(0xC000001DL)) +#define STATUS_NOT_IMPLEMENTED ((int)(0xC0000002L)) +#define STATUS_PENDING ((int)(0x00000103L)) +#define STATUS_ACCESS_DENIED ((int)(0xC0000022L)) +#define STATUS_BUFFER_TOO_SMALL ((int)(0xC0000023L)) +#define STATUS_OBJECT_TYPE_MISMATCH ((int)(0xC0000024L)) +#define STATUS_GRAPHICS_ALLOCATION_BUSY ((int)(0xC01E0102L)) +#define STATUS_NOT_SUPPORTED ((int)(0xC00000BBL)) +#define STATUS_TIMEOUT ((int)(0x00000102L)) +#define STATUS_INVALID_PARAMETER ((int)(0xC000000DL)) +#define STATUS_NO_MEMORY ((int)(0xC0000017L)) +#define STATUS_OBJECT_NAME_COLLISION ((int)(0xC0000035L)) +#define STATUS_OBJECT_NAME_NOT_FOUND ((int)(0xC0000034L)) + + +#define NT_SUCCESS(status) (status.v >=3D 0) + +#ifndef DEBUG + +#define DXGKRNL_ASSERT(exp) + +#else + +#define DXGKRNL_ASSERT(exp) \ +do { \ + if (!(exp)) { \ + dump_stack(); \ + BUG_ON(true); \ + } \ +} while (0) + +#endif /* DEBUG */ + +#endif /* _MISC_H_ */ diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 5d973604400c..2ea04cc02a1f 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -14,6 +14,40 @@ #ifndef _D3DKMTHK_H #define _D3DKMTHK_H =20 +/* + * This structure matches the definition of D3DKMTHANDLE in Windows. + * The handle is opaque in user mode. It is used by user mode applications= to + * represent kernel mode objects, created by dxgkrnl. + */ +struct d3dkmthandle { + union { + struct { + __u32 instance : 6; + __u32 index : 24; + __u32 unique : 2; + }; + __u32 v; + }; +}; + +/* + * VM bus messages return Windows' NTSTATUS, which is integer and only neg= ative + * value indicates a failure. A positive number is a success and needs to = be + * returned to user mode as the IOCTL return code. Negative status codes a= re + * converted to Linux error codes. + */ +struct ntstatus { + union { + struct { + int code : 16; + int facility : 13; + int customer : 1; + int severity : 2; + }; + int v; + }; +}; + /* * Matches the Windows LUID definition. * LUID is a locally unique identifier (similar to GUID, but not global), From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 21E983F7A86 for ; Thu, 19 Mar 2026 20:25:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951921; cv=none; b=uy8S0ujCBrvMMEm0We4L4M+GAEq2Iz1agoHmyeiFMq3mkeHQZGs9rrNaPG5rD04bN3Z8Ebw1sz3l7UrYCPAEn0DaCGxsUAL4u0bfnucfbQPm0U+rXnkdn+yElFGHmwjKLDraOXnzQuu6EJfsF5McqV7QV/zbjUna6DGDBitdfcQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951921; c=relaxed/simple; bh=EurVXR0Bo0PoBM3EFaeoyRoEn6hj+hD9ZjqDURb9/9M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=umjTYNJgiV3uG6Lx0HTpTiuJWxkz14ty9Vu95ThbUOzPy/v4Tn+nH7gbx3I88XSMbCfRqlPK8+hsKndsjSXbmFuCow+5wXhfUANVQZpBU2iCQHCRmLr6E1TYJQP6LYGMCXdEvXvpqHybIMkwL+x3ZkdAWqaYtUdfQ8SCYlbr9Aw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=beauo174; arc=none smtp.client-ip=209.85.221.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="beauo174" Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-43b4f48c47cso1042453f8f.0 for ; Thu, 19 Mar 2026 13:25:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951916; x=1774556716; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=X6veZ7Z/5z6EiBHg/NZ/zT+51+PY4RbSzn3T7r4lA98=; b=beauo174E5qLcZ93To7utG3Z02Nx3IuYq7UZuBig8uNtt8x5ZfhTIn+1artWvwbpYn V0xOWRZ2An1e0vx9YTiPUu9p6+11ZNX4ZUwm+pvzOy36S36gYMmAcKf6EIDXa8mxSw7k 1eGDnJqEKzaZgzAJ3LVe91ZxH6JRfifW2RY0gb3GcIpSM5MK8Vwe154pIlNY7ULiBUG2 tlPBHhFu8K8BGfufsWQh2ZJBlMdWxfZrmoQWGcRnrr3AxlNUpbBckFL0DV/rlIuhauKj 0+eQOT+uZEcn0gMIUeohAFWu+UOfUx2dj5+9Kr9M9SVtismCwY/R2BXoHJFRrmq6M6gj mZCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951916; x=1774556716; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=X6veZ7Z/5z6EiBHg/NZ/zT+51+PY4RbSzn3T7r4lA98=; b=jck3aPRxzo5rABTiS9HXjbT03AvfhePqu/1hpBD/CyiwpyQMhGqwOtqgy6uFPdj1ke tH6MtU55ludnHiKd70c5xoO2mDtI9wanxaHYKxJ7Z20+mUVZlIkDwkt9GOK56COaKw/W 0EyTSfnxtyj/Iwm4jUTESYIhi43huQOJDInITh/BjXbGLJC1qzJxMdxmd47xco+JrBAL 4aIo2ZD/A0TjRMriGTdBPUFmiQnvtOg/M5kYEE2dOYYabnGTN2ZILxxRdShOHUJctzeb tMEu6At3L35cjRkOnqC9pTJKIXVE9VUJH9aNANQwSAHx0E7dHe2j4rnu3rVh5ZxEtHkG gcDA== X-Gm-Message-State: AOJu0Yyd01h+sQt9BSiGKL0fsYzjemxzMpTC/YnvesWDV8qQw0zBE4Us 2Wx7FQTXiMApxGIlvwKgrkVqfus//ny7qXAKmEE6DeL7YnQE4F9U5qDp X-Gm-Gg: ATEYQzwXSbZDE5ETge1byZAvYMsYie28UFVuU0w9dwCfnS/FhvPHOsL+OExyw2tGF1+ oryrhbyqCxhN4JyE42mJdbop6gIhnmynoPb6Bx825gKxDXQC3S96nEmZRt4Z45erurlUAAtYYiM lmNhUedeLqU+sJeNLHDfuGaQG2NlUYXDxVc82jQX/9AFsjH9e44kLLhw/np9igKsEYadihzkkPS icd8hcDwJIloamMxBLqLaaG1etsV5OcQvQp8CQLbqrmxrqVWF9ul8XhJ8+aX/c+w7gMXYTDetTg pzxPPKaobbtta6wYnILqmK1wfnu1kBUDDnAQWOZjyEMlCgPqITW51HVGhSQbdDcRmJy92UfZ+7B fA7rNk+QVE77Bo3cL6KF/ph5PDHwolGsIk9z8MCRfDuyJ/VuKBVo2WYQmYHg3JeW6KbniIFEOO8 BVaRNkA+QQpU5k0XOpReEuC2NeiVNeizx2oZ6fRYaXf8HjDLnQ X-Received: by 2002:a05:6000:26c4:b0:43b:4ef0:e13 with SMTP id ffacd0b85a97d-43b6424e18emr1335928f8f.12.1773951916070; Thu, 19 Mar 2026 13:25:16 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.15 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:15 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 03/55] drivers: hv: dxgkrnl: Creation of dxgadapter object Date: Thu, 19 Mar 2026 20:24:17 +0000 Message-ID: <20260319202509.63802-4-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Handle creation and destruction of dxgadapter object, which represents a virtual compute device, projected to the VM by the host. The dxgadapter object is created when the corresponding VMBus channel is offered by Hyper-V. There could be multiple virtual compute device objects, projected by the host to VM. They are enumerated by issuing IOCTLs to the /dev/dxg device. The adapter object can start functioning only when the global VMBus channel and the corresponding per device VMBus channel are initialized. Notifications about arrival of a virtual compute PCI device and VMBus channels can happen in any order. Therefore, the initial dxgadapter object state is DXGADAPTER_STATE_WAITING_VMBUS. A list of VMBus channels and a list of waiting dxgadapter objects are maintained. When dxgkrnl is notified about a VMBus channel arrival, if tries to start all adapters, which are not started yet. Properties of the adapter object are determined by sending VMBus messages to the host to the corresponding VMBus channel. When the per virtual compute device VMBus channel or the global channel are destroyed, the adapter object is destroyed. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/Makefile | 2 +- drivers/hv/dxgkrnl/dxgadapter.c | 170 +++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 85 +++++++++++++ drivers/hv/dxgkrnl/dxgmodule.c | 204 +++++++++++++++++++++++++++++- drivers/hv/dxgkrnl/dxgvmbus.c | 217 +++++++++++++++++++++++++++++--- drivers/hv/dxgkrnl/dxgvmbus.h | 128 +++++++++++++++++++ drivers/hv/dxgkrnl/misc.c | 37 ++++++ drivers/hv/dxgkrnl/misc.h | 24 +++- 8 files changed, 844 insertions(+), 23 deletions(-) create mode 100644 drivers/hv/dxgkrnl/dxgadapter.c create mode 100644 drivers/hv/dxgkrnl/misc.c diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile index 76349064b60a..2ed07d877c91 100644 --- a/drivers/hv/dxgkrnl/Makefile +++ b/drivers/hv/dxgkrnl/Makefile @@ -2,4 +2,4 @@ # Makefile for the hyper-v compute device driver (dxgkrnl). =20 obj-$(CONFIG_DXGKRNL) +=3D dxgkrnl.o -dxgkrnl-y :=3D dxgmodule.o dxgvmbus.o +dxgkrnl-y :=3D dxgmodule.o misc.o dxgadapter.o ioctl.o dxgvmbus.o diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c new file mode 100644 index 000000000000..07d47699d255 --- /dev/null +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Implementation of dxgadapter and its objects + * + */ + +#include +#include +#include +#include + +#include "dxgkrnl.h" + +#undef pr_fmt +#define pr_fmt(fmt) "dxgk: " fmt + +int dxgadapter_set_vmbus(struct dxgadapter *adapter, struct hv_device *hde= v) +{ + int ret; + + guid_to_luid(&hdev->channel->offermsg.offer.if_instance, + &adapter->luid); + DXG_TRACE("%x:%x %p %pUb", + adapter->luid.b, adapter->luid.a, hdev->channel, + &hdev->channel->offermsg.offer.if_instance); + + ret =3D dxgvmbuschannel_init(&adapter->channel, hdev); + if (ret) + goto cleanup; + + adapter->channel.adapter =3D adapter; + adapter->hv_dev =3D hdev; + + ret =3D dxgvmb_send_open_adapter(adapter); + if (ret < 0) { + DXG_ERR("dxgvmb_send_open_adapter failed: %d", ret); + goto cleanup; + } + + ret =3D dxgvmb_send_get_internal_adapter_info(adapter); + +cleanup: + if (ret) + DXG_ERR("Failed to set vmbus: %d", ret); + return ret; +} + +void dxgadapter_start(struct dxgadapter *adapter) +{ + struct dxgvgpuchannel *ch =3D NULL; + struct dxgvgpuchannel *entry; + int ret; + struct dxgglobal *dxgglobal =3D dxggbl(); + + DXG_TRACE("%x-%x", adapter->luid.a, adapter->luid.b); + + /* Find the corresponding vGPU vm bus channel */ + list_for_each_entry(entry, &dxgglobal->vgpu_ch_list_head, + vgpu_ch_list_entry) { + if (memcmp(&adapter->luid, + &entry->adapter_luid, + sizeof(struct winluid)) =3D=3D 0) { + ch =3D entry; + break; + } + } + if (ch =3D=3D NULL) { + DXG_TRACE("vGPU chanel is not ready"); + return; + } + + /* The global channel is initialized when the first adapter starts */ + if (!dxgglobal->global_channel_initialized) { + ret =3D dxgglobal_init_global_channel(); + if (ret) { + dxgglobal_destroy_global_channel(); + return; + } + dxgglobal->global_channel_initialized =3D true; + } + + /* Initialize vGPU vm bus channel */ + ret =3D dxgadapter_set_vmbus(adapter, ch->hdev); + if (ret) { + DXG_ERR("Failed to start adapter %p", adapter); + adapter->adapter_state =3D DXGADAPTER_STATE_STOPPED; + return; + } + + adapter->adapter_state =3D DXGADAPTER_STATE_ACTIVE; + DXG_TRACE("Adapter started %p", adapter); +} + +void dxgadapter_stop(struct dxgadapter *adapter) +{ + bool adapter_stopped =3D false; + + down_write(&adapter->core_lock); + if (!adapter->stopping_adapter) + adapter->stopping_adapter =3D true; + else + adapter_stopped =3D true; + up_write(&adapter->core_lock); + + if (adapter_stopped) + return; + + if (dxgadapter_acquire_lock_exclusive(adapter) =3D=3D 0) { + dxgvmb_send_close_adapter(adapter); + dxgadapter_release_lock_exclusive(adapter); + } + dxgvmbuschannel_destroy(&adapter->channel); + + adapter->adapter_state =3D DXGADAPTER_STATE_STOPPED; +} + +void dxgadapter_release(struct kref *refcount) +{ + struct dxgadapter *adapter; + + adapter =3D container_of(refcount, struct dxgadapter, adapter_kref); + DXG_TRACE("%p", adapter); + kfree(adapter); +} + +bool dxgadapter_is_active(struct dxgadapter *adapter) +{ + return adapter->adapter_state =3D=3D DXGADAPTER_STATE_ACTIVE; +} + +int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter) +{ + down_write(&adapter->core_lock); + if (adapter->adapter_state !=3D DXGADAPTER_STATE_ACTIVE) { + dxgadapter_release_lock_exclusive(adapter); + return -ENODEV; + } + return 0; +} + +void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter) +{ + down_write(&adapter->core_lock); +} + +void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter) +{ + up_write(&adapter->core_lock); +} + +int dxgadapter_acquire_lock_shared(struct dxgadapter *adapter) +{ + down_read(&adapter->core_lock); + if (adapter->adapter_state =3D=3D DXGADAPTER_STATE_ACTIVE) + return 0; + dxgadapter_release_lock_shared(adapter); + return -ENODEV; +} + +void dxgadapter_release_lock_shared(struct dxgadapter *adapter) +{ + up_read(&adapter->core_lock); +} diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 52b9e82c51e6..ba2a7c6001aa 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -47,9 +47,39 @@ extern struct dxgdriver dxgdrv; =20 #define DXGDEV dxgdrv.dxgdev =20 +struct dxgk_device_types { + u32 post_device:1; + u32 post_device_certain:1; + u32 software_device:1; + u32 soft_gpu_device:1; + u32 warp_device:1; + u32 bdd_device:1; + u32 support_miracast:1; + u32 mismatched_lda:1; + u32 indirect_display_device:1; + u32 xbox_one_device:1; + u32 child_id_support_dwm_clone:1; + u32 child_id_support_dwm_clone2:1; + u32 has_internal_panel:1; + u32 rfx_vgpu_device:1; + u32 virtual_render_device:1; + u32 support_preserve_boot_display:1; + u32 is_uefi_frame_buffer:1; + u32 removable_device:1; + u32 virtual_monitor_device:1; +}; + +enum dxgobjectstate { + DXGOBJECTSTATE_CREATED, + DXGOBJECTSTATE_ACTIVE, + DXGOBJECTSTATE_STOPPED, + DXGOBJECTSTATE_DESTROYED, +}; + struct dxgvmbuschannel { struct vmbus_channel *channel; struct hv_device *hdev; + struct dxgadapter *adapter; spinlock_t packet_list_mutex; struct list_head packet_list_head; struct kmem_cache *packet_cache; @@ -81,6 +111,10 @@ struct dxgglobal { struct miscdevice dxgdevice; struct mutex device_mutex; =20 + /* list of created adapters */ + struct list_head adapter_list_head; + struct rw_semaphore adapter_list_lock; + /* * List of the vGPU VM bus channels (dxgvgpuchannel) * Protected by device_mutex @@ -102,6 +136,10 @@ static inline struct dxgglobal *dxggbl(void) return dxgdrv.dxgglobal; } =20 +int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid, + struct winluid host_vgpu_luid); +void dxgglobal_acquire_adapter_list_lock(enum dxglockstate state); +void dxgglobal_release_adapter_list_lock(enum dxglockstate state); int dxgglobal_init_global_channel(void); void dxgglobal_destroy_global_channel(void); struct vmbus_channel *dxgglobal_get_vmbus(void); @@ -113,6 +151,47 @@ struct dxgprocess { /* Placeholder */ }; =20 +enum dxgadapter_state { + DXGADAPTER_STATE_ACTIVE =3D 0, + DXGADAPTER_STATE_STOPPED =3D 1, + DXGADAPTER_STATE_WAITING_VMBUS =3D 2, +}; + +/* + * This object represents the grapchis adapter. + * Objects, which take reference on the adapter: + * - dxgglobal + * - adapter handle (struct d3dkmthandle) + */ +struct dxgadapter { + struct rw_semaphore core_lock; + struct kref adapter_kref; + /* Entry in the list of adapters in dxgglobal */ + struct list_head adapter_list_entry; + struct pci_dev *pci_dev; + struct hv_device *hv_dev; + struct dxgvmbuschannel channel; + struct d3dkmthandle host_handle; + enum dxgadapter_state adapter_state; + struct winluid host_adapter_luid; + struct winluid host_vgpu_luid; + struct winluid luid; /* VM bus channel luid */ + u16 device_description[80]; + u16 device_instance_id[WIN_MAX_PATH]; + bool stopping_adapter; +}; + +int dxgadapter_set_vmbus(struct dxgadapter *adapter, struct hv_device *hde= v); +bool dxgadapter_is_active(struct dxgadapter *adapter); +void dxgadapter_start(struct dxgadapter *adapter); +void dxgadapter_stop(struct dxgadapter *adapter); +void dxgadapter_release(struct kref *refcount); +int dxgadapter_acquire_lock_shared(struct dxgadapter *adapter); +void dxgadapter_release_lock_shared(struct dxgadapter *adapter); +int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter); +void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter); +void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter); + /* * The convention is that VNBus instance id is a GUID, but the host sets * the lower part of the value to the host adapter LUID. The function @@ -141,6 +220,12 @@ static inline void guid_to_luid(guid_t *guid, struct w= inluid *luid) =20 void dxgvmb_initialize(void); int dxgvmb_send_set_iospace_region(u64 start, u64 len); +int dxgvmb_send_open_adapter(struct dxgadapter *adapter); +int dxgvmb_send_close_adapter(struct dxgadapter *adapter); +int dxgvmb_send_get_internal_adapter_info(struct dxgadapter *adapter); +int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel, + void *command, + u32 cmd_size); =20 int ntstatus2int(struct ntstatus status); =20 diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index e55639dc0adc..ef80b920f010 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -55,6 +55,156 @@ void dxgglobal_release_channel_lock(void) up_read(&dxggbl()->channel_lock); } =20 +void dxgglobal_acquire_adapter_list_lock(enum dxglockstate state) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (state =3D=3D DXGLOCK_EXCL) + down_write(&dxgglobal->adapter_list_lock); + else + down_read(&dxgglobal->adapter_list_lock); +} + +void dxgglobal_release_adapter_list_lock(enum dxglockstate state) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (state =3D=3D DXGLOCK_EXCL) + up_write(&dxgglobal->adapter_list_lock); + else + up_read(&dxgglobal->adapter_list_lock); +} + +/* + * Returns a pointer to dxgadapter object, which corresponds to the given = PCI + * device, or NULL. + */ +static struct dxgadapter *find_pci_adapter(struct pci_dev *dev) +{ + struct dxgadapter *entry; + struct dxgadapter *adapter =3D NULL; + struct dxgglobal *dxgglobal =3D dxggbl(); + + dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL); + + list_for_each_entry(entry, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (dev =3D=3D entry->pci_dev) { + adapter =3D entry; + break; + } + } + + dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL); + return adapter; +} + +/* + * Returns a pointer to dxgadapter object, which has the givel LUID + * device, or NULL. + */ +static struct dxgadapter *find_adapter(struct winluid *luid) +{ + struct dxgadapter *entry; + struct dxgadapter *adapter =3D NULL; + struct dxgglobal *dxgglobal =3D dxggbl(); + + dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL); + + list_for_each_entry(entry, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (memcmp(luid, &entry->luid, sizeof(struct winluid)) =3D=3D 0) { + adapter =3D entry; + break; + } + } + + dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL); + return adapter; +} + +/* + * Creates a new dxgadapter object, which represents a virtual GPU, projec= ted + * by the host. + * The adapter is in the waiting state. It will become active when the glo= bal + * VM bus channel and the adapter VM bus channel are created. + */ +int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid, + struct winluid host_vgpu_luid) +{ + struct dxgadapter *adapter; + int ret =3D 0; + struct dxgglobal *dxgglobal =3D dxggbl(); + + adapter =3D kzalloc(sizeof(struct dxgadapter), GFP_KERNEL); + if (adapter =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + adapter->adapter_state =3D DXGADAPTER_STATE_WAITING_VMBUS; + adapter->host_vgpu_luid =3D host_vgpu_luid; + kref_init(&adapter->adapter_kref); + init_rwsem(&adapter->core_lock); + + adapter->pci_dev =3D dev; + guid_to_luid(guid, &adapter->luid); + + dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL); + + list_add_tail(&adapter->adapter_list_entry, + &dxgglobal->adapter_list_head); + dxgglobal->num_adapters++; + dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL); + + DXG_TRACE("new adapter added %p %x-%x", adapter, + adapter->luid.a, adapter->luid.b); +cleanup: + return ret; +} + +/* + * Attempts to start dxgadapter objects, which are not active yet. + */ +static void dxgglobal_start_adapters(void) +{ + struct dxgadapter *adapter; + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (dxgglobal->hdev =3D=3D NULL) { + DXG_TRACE("Global channel is not ready"); + return; + } + dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL); + list_for_each_entry(adapter, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (adapter->adapter_state =3D=3D DXGADAPTER_STATE_WAITING_VMBUS) + dxgadapter_start(adapter); + } + dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL); +} + +/* + * Stopsthe active dxgadapter objects. + */ +static void dxgglobal_stop_adapters(void) +{ + struct dxgadapter *adapter; + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (dxgglobal->hdev =3D=3D NULL) { + DXG_TRACE("Global channel is not ready"); + return; + } + dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL); + list_for_each_entry(adapter, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (adapter->adapter_state =3D=3D DXGADAPTER_STATE_ACTIVE) + dxgadapter_stop(adapter); + } + dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL); +} + const struct file_operations dxgk_fops =3D { .owner =3D THIS_MODULE, }; @@ -182,6 +332,15 @@ static int dxg_pci_probe_device(struct pci_dev *dev, DXG_TRACE("Vmbus interface version: %d", dxgglobal->vmbus_ver); DXG_TRACE("Host luid: %x-%x", vgpu_luid.b, vgpu_luid.a); =20 + /* Create new virtual GPU adapter */ + ret =3D dxgglobal_create_adapter(dev, &guid, vgpu_luid); + if (ret) + goto cleanup; + + /* Attempt to start the adapter in case VM bus channels are created */ + + dxgglobal_start_adapters(); + cleanup: =20 mutex_unlock(&dxgglobal->device_mutex); @@ -193,7 +352,25 @@ static int dxg_pci_probe_device(struct pci_dev *dev, =20 static void dxg_pci_remove_device(struct pci_dev *dev) { - /* Placeholder */ + struct dxgadapter *adapter; + struct dxgglobal *dxgglobal =3D dxggbl(); + + mutex_lock(&dxgglobal->device_mutex); + + adapter =3D find_pci_adapter(dev); + if (adapter) { + dxgglobal_acquire_adapter_list_lock(DXGLOCK_EXCL); + list_del(&adapter->adapter_list_entry); + dxgglobal->num_adapters--; + dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL); + + dxgadapter_stop(adapter); + kref_put(&adapter->adapter_kref, dxgadapter_release); + } else { + DXG_ERR("Failed to find dxgadapter for pcidev"); + } + + mutex_unlock(&dxgglobal->device_mutex); } =20 static struct pci_device_id dxg_pci_id_table[] =3D { @@ -297,6 +474,25 @@ void dxgglobal_destroy_global_channel(void) up_write(&dxgglobal->channel_lock); } =20 +static void dxgglobal_stop_adapter_vmbus(struct hv_device *hdev) +{ + struct dxgadapter *adapter =3D NULL; + struct winluid luid; + + guid_to_luid(&hdev->channel->offermsg.offer.if_instance, &luid); + + DXG_TRACE("Stopping adapter %x:%x", luid.b, luid.a); + + adapter =3D find_adapter(&luid); + + if (adapter && adapter->adapter_state =3D=3D DXGADAPTER_STATE_ACTIVE) { + down_write(&adapter->core_lock); + dxgvmbuschannel_destroy(&adapter->channel); + adapter->adapter_state =3D DXGADAPTER_STATE_STOPPED; + up_write(&adapter->core_lock); + } +} + static const struct hv_vmbus_device_id dxg_vmbus_id_table[] =3D { /* Per GPU Device GUID */ { HV_GPUP_DXGK_VGPU_GUID }, @@ -329,6 +525,7 @@ static int dxg_probe_vmbus(struct hv_device *hdev, vgpuch->hdev =3D 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) =3D=3D 0) { /* This is the global Dxgkgnl channel */ @@ -341,6 +538,7 @@ static int dxg_probe_vmbus(struct hv_device *hdev, goto error; } dxgglobal->hdev =3D hdev; + dxgglobal_start_adapters(); } else { /* Unknown device type */ DXG_ERR("Unknown VM bus device type"); @@ -364,6 +562,7 @@ static int dxg_remove_vmbus(struct hv_device *hdev) =20 if (uuid_le_cmp(hdev->dev_type, dxg_vmbus_id_table[0].guid) =3D=3D 0) { DXG_TRACE("Remove virtual GPU channel"); + dxgglobal_stop_adapter_vmbus(hdev); list_for_each_entry(vgpu_channel, &dxgglobal->vgpu_ch_list_head, vgpu_ch_list_entry) { @@ -420,6 +619,8 @@ static struct dxgglobal *dxgglobal_create(void) mutex_init(&dxgglobal->device_mutex); =20 INIT_LIST_HEAD(&dxgglobal->vgpu_ch_list_head); + INIT_LIST_HEAD(&dxgglobal->adapter_list_head); + init_rwsem(&dxgglobal->adapter_list_lock); =20 init_rwsem(&dxgglobal->channel_lock); =20 @@ -430,6 +631,7 @@ static void dxgglobal_destroy(struct dxgglobal *dxgglob= al) { if (dxgglobal) { mutex_lock(&dxgglobal->device_mutex); + dxgglobal_stop_adapters(); dxgglobal_destroy_global_channel(); mutex_unlock(&dxgglobal->device_mutex); =20 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index a4365739826a..6d4b8d9d8d07 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -77,7 +77,7 @@ struct dxgvmbusmsgres { void *res; }; =20 -static int init_message(struct dxgvmbusmsg *msg, +static int init_message(struct dxgvmbusmsg *msg, struct dxgadapter *adapte= r, struct dxgprocess *process, u32 size) { struct dxgglobal *dxgglobal =3D dxggbl(); @@ -99,10 +99,15 @@ static int init_message(struct dxgvmbusmsg *msg, if (use_ext_header) { msg->msg =3D (char *)&msg->hdr[1]; msg->hdr->command_offset =3D sizeof(msg->hdr[0]); + if (adapter) + msg->hdr->vgpu_luid =3D adapter->host_vgpu_luid; } else { msg->msg =3D (char *)msg->hdr; } - msg->channel =3D &dxgglobal->channel; + if (adapter && !dxgglobal->async_msg_enabled) + msg->channel =3D &adapter->channel; + else + msg->channel =3D &dxgglobal->channel; return 0; } =20 @@ -116,6 +121,37 @@ static void free_message(struct dxgvmbusmsg *msg, stru= ct dxgprocess *process) * Helper functions */ =20 +static void command_vm_to_host_init2(struct dxgkvmb_command_vm_to_host *co= mmand, + enum dxgkvmb_commandtype_global t, + struct d3dkmthandle process) +{ + command->command_type =3D t; + command->process =3D process; + command->command_id =3D 0; + command->channel_type =3D DXGKVMB_VM_TO_HOST; +} + +static void command_vgpu_to_host_init1(struct dxgkvmb_command_vgpu_to_host + *command, + enum dxgkvmb_commandtype type) +{ + command->command_type =3D type; + command->process.v =3D 0; + command->command_id =3D 0; + command->channel_type =3D DXGKVMB_VGPU_TO_HOST; +} + +static void command_vgpu_to_host_init2(struct dxgkvmb_command_vgpu_to_host + *command, + enum dxgkvmb_commandtype type, + struct d3dkmthandle process) +{ + command->command_type =3D type; + command->process =3D process; + command->command_id =3D 0; + command->channel_type =3D DXGKVMB_VGPU_TO_HOST; +} + int ntstatus2int(struct ntstatus status) { if (NT_SUCCESS(status)) @@ -216,22 +252,26 @@ static void process_inband_packet(struct dxgvmbuschan= nel *channel, u32 packet_length =3D hv_pkt_datalen(desc); struct dxgkvmb_command_host_to_vm *packet; =20 - if (packet_length < sizeof(struct dxgkvmb_command_host_to_vm)) { - DXG_ERR("Invalid global packet"); - } else { - packet =3D hv_pkt_data(desc); - DXG_TRACE("global packet %d", - packet->command_type); - switch (packet->command_type) { - case DXGK_VMBCOMMAND_SIGNALGUESTEVENT: - case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE: - break; - case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION: - break; - default: - DXG_ERR("unexpected host message %d", + if (channel->adapter =3D=3D NULL) { + if (packet_length < sizeof(struct dxgkvmb_command_host_to_vm)) { + DXG_ERR("Invalid global packet"); + } else { + packet =3D hv_pkt_data(desc); + DXG_TRACE("global packet %d", packet->command_type); + switch (packet->command_type) { + case DXGK_VMBCOMMAND_SIGNALGUESTEVENT: + case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE: + break; + case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION: + break; + default: + DXG_ERR("unexpected host message %d", + packet->command_type); + } } + } else { + DXG_ERR("Unexpected packet for adapter channel"); } } =20 @@ -279,6 +319,7 @@ void dxgvmbuschannel_receive(void *ctx) struct vmpacket_descriptor *desc; u32 packet_length =3D 0; =20 + DXG_TRACE("New adapter message: %p", channel->adapter); foreach_vmbus_pkt(desc, channel->channel) { packet_length =3D hv_pkt_datalen(desc); DXG_TRACE("next packet (id, size, type): %llu %d %d", @@ -302,6 +343,8 @@ int dxgvmb_send_sync_msg(struct dxgvmbuschannel *channe= l, { int ret; struct dxgvmbuspacket *packet =3D NULL; + struct dxgkvmb_command_vm_to_host *cmd1; + struct dxgkvmb_command_vgpu_to_host *cmd2; =20 if (cmd_size > DXG_MAX_VM_BUS_PACKET_SIZE || result_size > DXG_MAX_VM_BUS_PACKET_SIZE) { @@ -315,6 +358,16 @@ int dxgvmb_send_sync_msg(struct dxgvmbuschannel *chann= el, return -ENOMEM; } =20 + if (channel->adapter =3D=3D NULL) { + cmd1 =3D command; + DXG_TRACE("send_sync_msg global: %d %p %d %d", + cmd1->command_type, command, cmd_size, result_size); + } else { + cmd2 =3D command; + DXG_TRACE("send_sync_msg adapter: %d %p %d %d", + cmd2->command_type, command, cmd_size, result_size); + } + packet->request_id =3D atomic64_inc_return(&channel->packet_request_id); init_completion(&packet->wait); packet->buffer =3D result; @@ -358,6 +411,41 @@ int dxgvmb_send_sync_msg(struct dxgvmbuschannel *chann= el, return ret; } =20 +int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel, + void *command, + u32 cmd_size) +{ + int ret; + int try_count =3D 0; + + if (cmd_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("%s invalid data size", __func__); + return -EINVAL; + } + + if (channel->adapter) { + DXG_ERR("Async message sent to the adapter channel"); + return -EINVAL; + } + + do { + ret =3D vmbus_sendpacket(channel->channel, command, cmd_size, + 0, VM_PKT_DATA_INBAND, 0); + /* + * -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 =3D=3D -EAGAIN) { + usleep_range(1000, 2000); + try_count++; + } + } while (ret =3D=3D -EAGAIN && try_count < 5000); + if (ret < 0) + DXG_ERR("vmbus_sendpacket failed: %x", ret); + + return ret; +} + static int dxgvmb_send_sync_msg_ntstatus(struct dxgvmbuschannel *channel, void *command, u32 cmd_size) @@ -383,7 +471,7 @@ int dxgvmb_send_set_iospace_region(u64 start, u64 len) struct dxgvmbusmsg msg; struct dxgglobal *dxgglobal =3D dxggbl(); =20 - ret =3D init_message(&msg, NULL, sizeof(*command)); + ret =3D init_message(&msg, NULL, NULL, sizeof(*command)); if (ret) return ret; command =3D (void *)msg.msg; @@ -408,3 +496,98 @@ int dxgvmb_send_set_iospace_region(u64 start, u64 len) DXG_TRACE("Error: %d", ret); return ret; } + +/* + * Virtual GPU messages to the host + */ + +int dxgvmb_send_open_adapter(struct dxgadapter *adapter) +{ + int ret; + struct dxgkvmb_command_openadapter *command; + struct dxgkvmb_command_openadapter_return result =3D { }; + struct dxgvmbusmsg msg; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D init_message(&msg, adapter, NULL, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init1(&command->hdr, DXGK_VMBCOMMAND_OPENADAPTER); + command->vmbus_interface_version =3D dxgglobal->vmbus_ver; + command->vmbus_last_compatible_interface_version =3D + DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result.status); + adapter->host_handle =3D result.host_adapter_handle; + +cleanup: + free_message(&msg, NULL); + if (ret) + DXG_ERR("Failed to open adapter: %d", ret); + return ret; +} + +int dxgvmb_send_close_adapter(struct dxgadapter *adapter) +{ + int ret; + struct dxgkvmb_command_closeadapter *command; + struct dxgvmbusmsg msg; + + ret =3D init_message(&msg, adapter, NULL, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init1(&command->hdr, DXGK_VMBCOMMAND_CLOSEADAPTER); + command->host_handle =3D adapter->host_handle; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + NULL, 0); + free_message(&msg, NULL); + if (ret) + DXG_ERR("Failed to close adapter: %d", ret); + return ret; +} + +int dxgvmb_send_get_internal_adapter_info(struct dxgadapter *adapter) +{ + int ret; + struct dxgkvmb_command_getinternaladapterinfo *command; + struct dxgkvmb_command_getinternaladapterinfo_return result =3D { }; + struct dxgvmbusmsg msg; + u32 result_size =3D sizeof(result); + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D init_message(&msg, adapter, NULL, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init1(&command->hdr, + DXGK_VMBCOMMAND_GETINTERNALADAPTERINFO); + if (dxgglobal->vmbus_ver < DXGK_VMBUS_INTERFACE_VERSION) + result_size -=3D sizeof(struct winluid); + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, result_size); + if (ret >=3D 0) { + adapter->host_adapter_luid =3D result.host_adapter_luid; + adapter->host_vgpu_luid =3D result.host_vgpu_luid; + wcsncpy(adapter->device_description, result.device_description, + sizeof(adapter->device_description) / sizeof(u16)); + wcsncpy(adapter->device_instance_id, result.device_instance_id, + sizeof(adapter->device_instance_id) / sizeof(u16)); + dxgglobal->async_msg_enabled =3D result.async_msg_enabled !=3D 0; + } + free_message(&msg, NULL); + if (ret) + DXG_ERR("Failed to get adapter info: %d", ret); + return ret; +} diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index b1bdd6039b73..584cdd3db6c0 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -47,6 +47,83 @@ enum dxgkvmb_commandtype_global { DXGK_VMBCOMMAND_INVALID_VM_TO_HOST }; =20 +/* + * + * Commands, sent to the host via the per adapter VM bus channel + * DXG_GUEST_VGPU_VMBUS + * + */ + +enum dxgkvmb_commandtype { + DXGK_VMBCOMMAND_CREATEDEVICE =3D 0, + DXGK_VMBCOMMAND_DESTROYDEVICE =3D 1, + DXGK_VMBCOMMAND_QUERYADAPTERINFO =3D 2, + DXGK_VMBCOMMAND_DDIQUERYADAPTERINFO =3D 3, + DXGK_VMBCOMMAND_CREATEALLOCATION =3D 4, + DXGK_VMBCOMMAND_DESTROYALLOCATION =3D 5, + DXGK_VMBCOMMAND_CREATECONTEXTVIRTUAL =3D 6, + DXGK_VMBCOMMAND_DESTROYCONTEXT =3D 7, + DXGK_VMBCOMMAND_CREATESYNCOBJECT =3D 8, + DXGK_VMBCOMMAND_CREATEPAGINGQUEUE =3D 9, + DXGK_VMBCOMMAND_DESTROYPAGINGQUEUE =3D 10, + DXGK_VMBCOMMAND_MAKERESIDENT =3D 11, + DXGK_VMBCOMMAND_EVICT =3D 12, + DXGK_VMBCOMMAND_ESCAPE =3D 13, + DXGK_VMBCOMMAND_OPENADAPTER =3D 14, + DXGK_VMBCOMMAND_CLOSEADAPTER =3D 15, + DXGK_VMBCOMMAND_FREEGPUVIRTUALADDRESS =3D 16, + DXGK_VMBCOMMAND_MAPGPUVIRTUALADDRESS =3D 17, + DXGK_VMBCOMMAND_RESERVEGPUVIRTUALADDRESS =3D 18, + DXGK_VMBCOMMAND_UPDATEGPUVIRTUALADDRESS =3D 19, + DXGK_VMBCOMMAND_SUBMITCOMMAND =3D 20, + dxgk_vmbcommand_queryvideomemoryinfo =3D 21, + DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMCPU =3D 22, + DXGK_VMBCOMMAND_LOCK2 =3D 23, + DXGK_VMBCOMMAND_UNLOCK2 =3D 24, + DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMGPU =3D 25, + DXGK_VMBCOMMAND_SIGNALSYNCOBJECT =3D 26, + DXGK_VMBCOMMAND_SIGNALFENCENTSHAREDBYREF =3D 27, + DXGK_VMBCOMMAND_GETDEVICESTATE =3D 28, + DXGK_VMBCOMMAND_MARKDEVICEASERROR =3D 29, + DXGK_VMBCOMMAND_ADAPTERSTOP =3D 30, + DXGK_VMBCOMMAND_SETQUEUEDLIMIT =3D 31, + DXGK_VMBCOMMAND_OPENRESOURCE =3D 32, + DXGK_VMBCOMMAND_SETCONTEXTSCHEDULINGPRIORITY =3D 33, + DXGK_VMBCOMMAND_PRESENTHISTORYTOKEN =3D 34, + DXGK_VMBCOMMAND_SETREDIRECTEDFLIPFENCEVALUE =3D 35, + DXGK_VMBCOMMAND_GETINTERNALADAPTERINFO =3D 36, + DXGK_VMBCOMMAND_FLUSHHEAPTRANSITIONS =3D 37, + DXGK_VMBCOMMAND_BLT =3D 38, + DXGK_VMBCOMMAND_DDIGETSTANDARDALLOCATIONDRIVERDATA =3D 39, + DXGK_VMBCOMMAND_CDDGDICOMMAND =3D 40, + DXGK_VMBCOMMAND_QUERYALLOCATIONRESIDENCY =3D 41, + DXGK_VMBCOMMAND_FLUSHDEVICE =3D 42, + DXGK_VMBCOMMAND_FLUSHADAPTER =3D 43, + DXGK_VMBCOMMAND_DDIGETNODEMETADATA =3D 44, + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE =3D 45, + DXGK_VMBCOMMAND_ISSYNCOBJECTSIGNALED =3D 46, + DXGK_VMBCOMMAND_CDDSYNCGPUACCESS =3D 47, + DXGK_VMBCOMMAND_QUERYSTATISTICS =3D 48, + DXGK_VMBCOMMAND_CHANGEVIDEOMEMORYRESERVATION =3D 49, + DXGK_VMBCOMMAND_CREATEHWQUEUE =3D 50, + DXGK_VMBCOMMAND_DESTROYHWQUEUE =3D 51, + DXGK_VMBCOMMAND_SUBMITCOMMANDTOHWQUEUE =3D 52, + DXGK_VMBCOMMAND_GETDRIVERSTOREFILE =3D 53, + DXGK_VMBCOMMAND_READDRIVERSTOREFILE =3D 54, + DXGK_VMBCOMMAND_GETNEXTHARDLINK =3D 55, + DXGK_VMBCOMMAND_UPDATEALLOCATIONPROPERTY =3D 56, + DXGK_VMBCOMMAND_OFFERALLOCATIONS =3D 57, + DXGK_VMBCOMMAND_RECLAIMALLOCATIONS =3D 58, + DXGK_VMBCOMMAND_SETALLOCATIONPRIORITY =3D 59, + DXGK_VMBCOMMAND_GETALLOCATIONPRIORITY =3D 60, + DXGK_VMBCOMMAND_GETCONTEXTSCHEDULINGPRIORITY =3D 61, + DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION =3D 62, + DXGK_VMBCOMMAND_QUERYRESOURCEINFO =3D 64, + DXGK_VMBCOMMAND_LOGEVENT =3D 65, + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES =3D 66, + DXGK_VMBCOMMAND_INVALID +}; + /* * Commands, sent by the host to the VM */ @@ -66,6 +143,15 @@ struct dxgkvmb_command_vm_to_host { enum dxgkvmb_commandtype_global command_type; }; =20 +struct dxgkvmb_command_vgpu_to_host { + u64 command_id; + struct d3dkmthandle process; + u32 channel_type : 8; + u32 async_msg : 1; + u32 reserved : 23; + enum dxgkvmb_commandtype command_type; +}; + struct dxgkvmb_command_host_to_vm { u64 command_id; struct d3dkmthandle process; @@ -83,4 +169,46 @@ struct dxgkvmb_command_setiospaceregion { u32 shared_page_gpadl; }; =20 +struct dxgkvmb_command_openadapter { + struct dxgkvmb_command_vgpu_to_host hdr; + u32 vmbus_interface_version; + u32 vmbus_last_compatible_interface_version; + struct winluid guest_adapter_luid; +}; + +struct dxgkvmb_command_openadapter_return { + struct d3dkmthandle host_adapter_handle; + struct ntstatus status; + u32 vmbus_interface_version; + u32 vmbus_last_compatible_interface_version; +}; + +struct dxgkvmb_command_closeadapter { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle host_handle; +}; + +struct dxgkvmb_command_getinternaladapterinfo { + struct dxgkvmb_command_vgpu_to_host hdr; +}; + +struct dxgkvmb_command_getinternaladapterinfo_return { + struct dxgk_device_types device_types; + u32 driver_store_copy_mode; + u32 driver_ddi_version; + u32 secure_virtual_machine : 1; + u32 virtual_machine_reset : 1; + u32 is_vail_supported : 1; + u32 hw_sch_enabled : 1; + u32 hw_sch_capable : 1; + u32 va_backed_vm : 1; + u32 async_msg_enabled : 1; + u32 hw_support_state : 2; + u32 reserved : 23; + struct winluid host_adapter_luid; + u16 device_description[80]; + u16 device_instance_id[WIN_MAX_PATH]; + struct winluid host_vgpu_luid; +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/misc.c b/drivers/hv/dxgkrnl/misc.c new file mode 100644 index 000000000000..cb1e0635bebc --- /dev/null +++ b/drivers/hv/dxgkrnl/misc.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2019, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Helper functions + * + */ + +#include +#include +#include + +#include "dxgkrnl.h" +#include "misc.h" + +#undef pr_fmt +#define pr_fmt(fmt) "dxgk: " fmt + +u16 *wcsncpy(u16 *dest, const u16 *src, size_t n) +{ + int i; + + for (i =3D 0; i < n; i++) { + dest[i] =3D src[i]; + if (src[i] =3D=3D 0) { + i++; + break; + } + } + dest[i - 1] =3D 0; + return dest; +} diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h index 4c6047c32a20..d292e9a9bb7f 100644 --- a/drivers/hv/dxgkrnl/misc.h +++ b/drivers/hv/dxgkrnl/misc.h @@ -14,18 +14,34 @@ #ifndef _MISC_H_ #define _MISC_H_ =20 +/* Max characters in Windows path */ +#define WIN_MAX_PATH 260 + extern const struct d3dkmthandle zerohandle; =20 /* * Synchronization lock hierarchy. * - * The higher enum value, the higher is the lock order. - * When a lower lock ois held, the higher lock should not be acquired. + * The locks here are in the order from lowest to highest. + * When a lower lock is held, the higher lock should not be acquired. * - * channel_lock - * device_mutex + * channel_lock (VMBus channel lock) + * fd_mutex + * plistmutex (process list mutex) + * table_lock (handle table lock) + * core_lock (dxgadapter lock) + * device_lock (dxgdevice lock) + * adapter_list_lock + * device_mutex (dxgglobal mutex) */ =20 +u16 *wcsncpy(u16 *dest, const u16 *src, size_t n); + +enum dxglockstate { + DXGLOCK_SHARED, + DXGLOCK_EXCL +}; + /* * Some of the Windows return codes, which needs to be translated to Linux * IOCTL return codes. Positive values are success codes and need to be From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53E683F7E80 for ; Thu, 19 Mar 2026 20:25:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951923; cv=none; b=BmkwvY49tP+O3+LNjnERSWpuPY0siLuE8sZs2A5FHDc7hsONjAntpAWmKHdBkDkxoNhrEp46HGpUwzhLg+fXPjRIhCqpvY4wukYYgUs6jtuJ2hz3xOjPPftTdd7Z/VJeRqhL1wMEJiFePlRcXzH2sOUNFCi9nG7dmWa+qre3Co8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951923; c=relaxed/simple; bh=mpxogzttqGY2RdWi+DEFWY0TBddMViPrUSqcjrOXYUg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=moSuxQPDEBsD87j9iRrVvC39semsQnxMrCZaOVK26jU99m/a8Bw64sVBvu07SMP2tj1LrJnCOHxsmj7i1/DWmFN9PgCvZwOzPoDbnyFsIHpdTemlGSPxMjJQfENwmDyKyTY6BBb6Vm6jc07bQABuQlRcsLc0pS0SehRHvM0svHU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=e2WYGxAp; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="e2WYGxAp" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-485392de558so9135135e9.1 for ; Thu, 19 Mar 2026 13:25:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951918; x=1774556718; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=aQmUt8PE03Mo2YFvmbyVRyjPor6QZPpPG2GHlQ6KxFI=; b=e2WYGxApfteDMeNfmsoOPnZ440Q+TkwOcpPjksgxI/9o2GNHVvVJKbNJW5v4obkNd4 pHYDXmtAB9AGQdSv37Ckzi5gx70OSVKiLmjHmbKYJaSD8B4NzANv09G/3V2cxiBiLOuv 4eqw24cLMjpKc0bRiKzV9AXxjQ2ULEzTdtcXFS4CgZJCjkjNgCMFogcMtLdAdpXwa6+9 mzMCVqE0D2qVuWLvRZTJeViwwBDcR9cUPyZLE+kXHi1YooVZOx2Wa1k7o+tPbtnWocAY Jp+McMVKlwmIbc+v52wFodDgoGSry4a8bAzxmo65PAcNRfkFBeF4OVCJTroxxb//aOZ4 AhLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951918; x=1774556718; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=aQmUt8PE03Mo2YFvmbyVRyjPor6QZPpPG2GHlQ6KxFI=; b=ftcvcRAVaTL2pi5fXG8Y4RK0n2ZsYdqhTWRcUgdfyVYRtMtrrX/BYGXmCg/g/uRE8P 84HA0uniBJ/d0Nng3FS2yKYUaBVpJlQ/sOsxkaOdaJ1ppBtdWdrTeceM/z/uKuMhQ7gY Akndx2POon3I3xSbsA9W4Dau28EWrqiAGy96DcurGlH/PH0MjeB7niSWzzsQZml0EZEE eSWg2YbiU2Nlmbi3TWhVjrh17jZMa6AI2Rc1K9Ry4+qBOgTAWHohcaQVjRlzIXWcIzID AzHk+b3y96Ieg44FjVzD3F7GM4cwWrwqoNPVPqwA77tZokXmuWhIxOMS7hzBAxW2UMGM yhNw== X-Gm-Message-State: AOJu0YysMCehyQk1BgLbaLZ50SAAxEpKjHndiEIwQDJw/FnnJq3CVvpL iHi5QlwSE/qDHw4ZDdGtMCfI12yhY7U3GHrOYUVUNv7WSA7DFQ1OdCsCDUhgTrcQof4= X-Gm-Gg: ATEYQzzE2llH72L6+goYyJOA0HN9AJF7m0igWbBQHs2ElAF1gd6niqu3eeaSz0hUgwv C4GbHtKLiKGry991XXmQfl2Ts4kx8kvJWdquxkESi5hJ+JaVDidLKs+r3wYBhTTZATuCr/2yQrx 8BELqpe7+GdUw8Aw4YrsqfWOhaQqoZRWs5MCcX4UsyZGlOc67W7qdePG44fdA1VpFvg7NWspU2h aF4i8XK++fIntDMcjadaCO9KTuURu5z6asB1WwYRPwo2T5n9SSLUNgztCDMaKWbe/junyg77XAs jNpKlWakXO5kmu9j1QfoG5TiOiGrbEH7PWEytcMAaxWIpASEycLfIWY/0Q6zsHoKbOv98zfzlmE 9BnEE/jxp+THg8JMvGFYlMinCOi5RA1i8XULV0TJM5UMEDakJgCU3PYc34o8LxeIovKKbmVIX0Q 2z3qw71N1M07KaK3ktcHz1rbQD8apr3EdScEVVxNV2PqAnQ0ci X-Received: by 2002:a05:600c:3112:b0:485:3f72:323f with SMTP id 5b1f17b1804b1-486fedb8c6emr7194075e9.11.1773951917225; Thu, 19 Mar 2026 13:25:17 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.16 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:16 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 04/55] drivers: hv: dxgkrnl: Opening of /dev/dxg device and dxgprocess creation Date: Thu, 19 Mar 2026 20:24:18 +0000 Message-ID: <20260319202509.63802-5-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov - Implement opening of the device (/dev/dxg) file object and creation of dxgprocess objects. - Add VM bus messages to create and destroy the host side of a dxgprocess object. - Implement the handle manager, which manages d3dkmthandle handles for the internal process objects. The handles are used by a user mode client to reference dxgkrnl objects. dxgprocess is created for each process, which opens /dev/dxg. dxgprocess is ref counted, so the existing dxgprocess objects is used for a process, which opens the device object multiple time. dxgprocess is destroyed when the file object is released. A corresponding dxgprocess object is created on the host for every dxgprocess object in the guest. When a dxgkrnl object is created, in most cases the corresponding object is created in the host. The VM references the host objects by handles (d3dkmthandle). d3dkmthandle values for a host object and the corresponding VM object are the same. A host handle is allocated first and its value is assigned to the guest object. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/Makefile | 2 +- drivers/hv/dxgkrnl/dxgadapter.c | 72 ++++ drivers/hv/dxgkrnl/dxgkrnl.h | 95 +++++- drivers/hv/dxgkrnl/dxgmodule.c | 97 ++++++ drivers/hv/dxgkrnl/dxgprocess.c | 262 +++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.c | 164 ++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 36 ++ drivers/hv/dxgkrnl/hmgr.c | 563 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/hmgr.h | 112 +++++++ drivers/hv/dxgkrnl/ioctl.c | 60 ++++ drivers/hv/dxgkrnl/misc.h | 9 +- include/uapi/misc/d3dkmthk.h | 103 ++++++ 12 files changed, 1569 insertions(+), 6 deletions(-) create mode 100644 drivers/hv/dxgkrnl/dxgprocess.c create mode 100644 drivers/hv/dxgkrnl/hmgr.c create mode 100644 drivers/hv/dxgkrnl/hmgr.h diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile index 2ed07d877c91..9d821e83448a 100644 --- a/drivers/hv/dxgkrnl/Makefile +++ b/drivers/hv/dxgkrnl/Makefile @@ -2,4 +2,4 @@ # Makefile for the hyper-v compute device driver (dxgkrnl). =20 obj-$(CONFIG_DXGKRNL) +=3D dxgkrnl.o -dxgkrnl-y :=3D dxgmodule.o misc.o dxgadapter.o ioctl.o dxgvmbus.o +dxgkrnl-y :=3D dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o = dxgprocess.o diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index 07d47699d255..fa0d6beca157 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -100,6 +100,7 @@ void dxgadapter_start(struct dxgadapter *adapter) =20 void dxgadapter_stop(struct dxgadapter *adapter) { + struct dxgprocess_adapter *entry; bool adapter_stopped =3D false; =20 down_write(&adapter->core_lock); @@ -112,6 +113,15 @@ void dxgadapter_stop(struct dxgadapter *adapter) if (adapter_stopped) return; =20 + dxgglobal_acquire_process_adapter_lock(); + + list_for_each_entry(entry, &adapter->adapter_process_list_head, + adapter_process_list_entry) { + dxgprocess_adapter_stop(entry); + } + + dxgglobal_release_process_adapter_lock(); + if (dxgadapter_acquire_lock_exclusive(adapter) =3D=3D 0) { dxgvmb_send_close_adapter(adapter); dxgadapter_release_lock_exclusive(adapter); @@ -135,6 +145,21 @@ bool dxgadapter_is_active(struct dxgadapter *adapter) return adapter->adapter_state =3D=3D DXGADAPTER_STATE_ACTIVE; } =20 +/* Protected by dxgglobal_acquire_process_adapter_lock */ +void dxgadapter_add_process(struct dxgadapter *adapter, + struct dxgprocess_adapter *process_info) +{ + DXG_TRACE("%p %p", adapter, process_info); + list_add_tail(&process_info->adapter_process_list_entry, + &adapter->adapter_process_list_head); +} + +void dxgadapter_remove_process(struct dxgprocess_adapter *process_info) +{ + DXG_TRACE("%p %p", process_info->adapter, process_info); + list_del(&process_info->adapter_process_list_entry); +} + int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter) { down_write(&adapter->core_lock); @@ -168,3 +193,50 @@ void dxgadapter_release_lock_shared(struct dxgadapter = *adapter) { up_read(&adapter->core_lock); } + +struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *pr= ocess, + struct dxgadapter *adapter) +{ + struct dxgprocess_adapter *adapter_info; + + adapter_info =3D kzalloc(sizeof(*adapter_info), GFP_KERNEL); + if (adapter_info) { + if (kref_get_unless_zero(&adapter->adapter_kref) =3D=3D 0) { + DXG_ERR("failed to acquire adapter reference"); + goto cleanup; + } + adapter_info->adapter =3D adapter; + adapter_info->process =3D process; + adapter_info->refcount =3D 1; + list_add_tail(&adapter_info->process_adapter_list_entry, + &process->process_adapter_list_head); + dxgadapter_add_process(adapter, adapter_info); + } + return adapter_info; +cleanup: + if (adapter_info) + kfree(adapter_info); + return NULL; +} + +void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info) +{ +} + +void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info) +{ + dxgadapter_remove_process(adapter_info); + kref_put(&adapter_info->adapter->adapter_kref, dxgadapter_release); + list_del(&adapter_info->process_adapter_list_entry); + kfree(adapter_info); +} + +/* + * Must be called when dxgglobal::process_adapter_mutex is held + */ +void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter_info) +{ + adapter_info->refcount--; + if (adapter_info->refcount =3D=3D 0) + dxgprocess_adapter_destroy(adapter_info); +} diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index ba2a7c6001aa..b089d126f801 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -29,8 +29,10 @@ #include #include #include "misc.h" +#include "hmgr.h" #include =20 +struct dxgprocess; struct dxgadapter; =20 /* @@ -111,6 +113,10 @@ struct dxgglobal { struct miscdevice dxgdevice; struct mutex device_mutex; =20 + /* list of created processes */ + struct list_head plisthead; + struct mutex plistmutex; + /* list of created adapters */ struct list_head adapter_list_head; struct rw_semaphore adapter_list_lock; @@ -124,6 +130,9 @@ struct dxgglobal { /* protects acces to the global VM bus channel */ struct rw_semaphore channel_lock; =20 + /* protects the dxgprocess_adapter lists */ + struct mutex process_adapter_mutex; + bool global_channel_initialized; bool async_msg_enabled; bool misc_registered; @@ -144,13 +153,84 @@ int dxgglobal_init_global_channel(void); void dxgglobal_destroy_global_channel(void); struct vmbus_channel *dxgglobal_get_vmbus(void); struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel(void); +void dxgglobal_acquire_process_adapter_lock(void); +void dxgglobal_release_process_adapter_lock(void); int dxgglobal_acquire_channel_lock(void); void dxgglobal_release_channel_lock(void); =20 +/* + * Describes adapter information for each process + */ +struct dxgprocess_adapter { + /* Entry in dxgadapter::adapter_process_list_head */ + struct list_head adapter_process_list_entry; + /* Entry in dxgprocess::process_adapter_list_head */ + struct list_head process_adapter_list_entry; + struct dxgadapter *adapter; + struct dxgprocess *process; + int refcount; +}; + +struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *pr= ocess, + struct dxgadapter + *adapter); +void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter); +void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info); +void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info); + +/* + * The structure represents a process, which opened the /dev/dxg device. + * A corresponding object is created on the host. + */ struct dxgprocess { - /* Placeholder */ + /* + * Process list entry in dxgglobal. + * Protected by the dxgglobal->plistmutex. + */ + struct list_head plistentry; + pid_t pid; + pid_t tgid; + /* how many time the process was opened */ + struct kref process_kref; + /* + * This handle table is used for all objects except dxgadapter + * The handle table lock order is higher than the local_handle_table + * lock + */ + struct hmgrtable handle_table; + /* + * This handle table is used for dxgadapter objects. + * The handle table lock order is lowest. + */ + struct hmgrtable local_handle_table; + /* Handle of the corresponding objec on the host */ + struct d3dkmthandle host_handle; + + /* List of opened adapters (dxgprocess_adapter) */ + struct list_head process_adapter_list_head; }; =20 +struct dxgprocess *dxgprocess_create(void); +void dxgprocess_destroy(struct dxgprocess *process); +void dxgprocess_release(struct kref *refcount); +int dxgprocess_open_adapter(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle *handle); +int dxgprocess_close_adapter(struct dxgprocess *process, + struct d3dkmthandle handle); +struct dxgadapter *dxgprocess_get_adapter(struct dxgprocess *process, + struct d3dkmthandle handle); +struct dxgadapter *dxgprocess_adapter_by_handle(struct dxgprocess *process, + struct d3dkmthandle handle); +void dxgprocess_ht_lock_shared_down(struct dxgprocess *process); +void dxgprocess_ht_lock_shared_up(struct dxgprocess *process); +void dxgprocess_ht_lock_exclusive_down(struct dxgprocess *process); +void dxgprocess_ht_lock_exclusive_up(struct dxgprocess *process); +struct dxgprocess_adapter *dxgprocess_get_adapter_info(struct dxgprocess + *process, + struct dxgadapter + *adapter); + enum dxgadapter_state { DXGADAPTER_STATE_ACTIVE =3D 0, DXGADAPTER_STATE_STOPPED =3D 1, @@ -168,6 +248,8 @@ struct dxgadapter { struct kref adapter_kref; /* Entry in the list of adapters in dxgglobal */ struct list_head adapter_list_entry; + /* The list of dxgprocess_adapter entries */ + struct list_head adapter_process_list_head; struct pci_dev *pci_dev; struct hv_device *hv_dev; struct dxgvmbuschannel channel; @@ -191,6 +273,12 @@ void dxgadapter_release_lock_shared(struct dxgadapter = *adapter); int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter); void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter); void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter); +void dxgadapter_add_process(struct dxgadapter *adapter, + struct dxgprocess_adapter *process_info); +void dxgadapter_remove_process(struct dxgprocess_adapter *process_info); + +long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2); +long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2= ); =20 /* * The convention is that VNBus instance id is a GUID, but the host sets @@ -220,9 +308,14 @@ static inline void guid_to_luid(guid_t *guid, struct w= inluid *luid) =20 void dxgvmb_initialize(void); int dxgvmb_send_set_iospace_region(u64 start, u64 len); +int dxgvmb_send_create_process(struct dxgprocess *process); +int dxgvmb_send_destroy_process(struct d3dkmthandle process); int dxgvmb_send_open_adapter(struct dxgadapter *adapter); int dxgvmb_send_close_adapter(struct dxgadapter *adapter); int dxgvmb_send_get_internal_adapter_info(struct dxgadapter *adapter); +int dxgvmb_send_query_adapter_info(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryadapterinfo *args); int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel, void *command, u32 cmd_size); diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index ef80b920f010..17c22001ca6c 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -123,6 +123,20 @@ static struct dxgadapter *find_adapter(struct winluid = *luid) return adapter; } =20 +void dxgglobal_acquire_process_adapter_lock(void) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + mutex_lock(&dxgglobal->process_adapter_mutex); +} + +void dxgglobal_release_process_adapter_lock(void) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + mutex_unlock(&dxgglobal->process_adapter_mutex); +} + /* * Creates a new dxgadapter object, which represents a virtual GPU, projec= ted * by the host. @@ -147,6 +161,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_= t *guid, kref_init(&adapter->adapter_kref); init_rwsem(&adapter->core_lock); =20 + INIT_LIST_HEAD(&adapter->adapter_process_list_head); adapter->pci_dev =3D dev; guid_to_luid(guid, &adapter->luid); =20 @@ -205,8 +220,87 @@ static void dxgglobal_stop_adapters(void) dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL); } =20 +/* + * Returns dxgprocess for the current executing process. + * Creates dxgprocess if it doesn't exist. + */ +static struct dxgprocess *dxgglobal_get_current_process(void) +{ + /* + * Find the DXG process for the current process. + * A new process is created if necessary. + */ + struct dxgprocess *process =3D NULL; + struct dxgprocess *entry =3D NULL; + struct dxgglobal *dxgglobal =3D dxggbl(); + + mutex_lock(&dxgglobal->plistmutex); + list_for_each_entry(entry, &dxgglobal->plisthead, plistentry) { + /* All threads of a process have the same thread group ID */ + if (entry->tgid =3D=3D current->tgid) { + if (kref_get_unless_zero(&entry->process_kref)) { + process =3D entry; + DXG_TRACE("found dxgprocess"); + } else { + DXG_TRACE("process is destroyed"); + } + break; + } + } + mutex_unlock(&dxgglobal->plistmutex); + + if (process =3D=3D NULL) + process =3D dxgprocess_create(); + + return process; +} + +/* + * File operations for the /dev/dxg device + */ + +static int dxgk_open(struct inode *n, struct file *f) +{ + int ret =3D 0; + struct dxgprocess *process; + + DXG_TRACE("%p %d %d", f, current->pid, current->tgid); + + /* Find/create a dxgprocess structure for this process */ + process =3D dxgglobal_get_current_process(); + + if (process) { + f->private_data =3D process; + } else { + DXG_TRACE("cannot create dxgprocess"); + ret =3D -EBADF; + } + + return ret; +} + +static int dxgk_release(struct inode *n, struct file *f) +{ + struct dxgprocess *process; + + process =3D (struct dxgprocess *)f->private_data; + DXG_TRACE("%p, %p", f, process); + + if (process =3D=3D NULL) + return -EINVAL; + + kref_put(&process->process_kref, dxgprocess_release); + + f->private_data =3D NULL; + return 0; +} + const struct file_operations dxgk_fops =3D { .owner =3D THIS_MODULE, + .open =3D dxgk_open, + .release =3D dxgk_release, + .compat_ioctl =3D dxgk_compat_ioctl, + .unlocked_ioctl =3D dxgk_unlocked_ioctl, }; =20 /* @@ -616,7 +710,10 @@ static struct dxgglobal *dxgglobal_create(void) if (!dxgglobal) return NULL; =20 + INIT_LIST_HEAD(&dxgglobal->plisthead); + mutex_init(&dxgglobal->plistmutex); mutex_init(&dxgglobal->device_mutex); + mutex_init(&dxgglobal->process_adapter_mutex); =20 INIT_LIST_HEAD(&dxgglobal->vgpu_ch_list_head); INIT_LIST_HEAD(&dxgglobal->adapter_list_head); diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.c new file mode 100644 index 000000000000..ab9a01e3c8c8 --- /dev/null +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * DXGPROCESS implementation + * + */ + +#include "dxgkrnl.h" + +#undef pr_fmt +#define pr_fmt(fmt) "dxgk: " fmt + +/* + * Creates a new dxgprocess object + * Must be called when dxgglobal->plistmutex is held + */ +struct dxgprocess *dxgprocess_create(void) +{ + struct dxgprocess *process; + int ret; + struct dxgglobal *dxgglobal =3D dxggbl(); + + process =3D kzalloc(sizeof(struct dxgprocess), GFP_KERNEL); + if (process !=3D NULL) { + DXG_TRACE("new dxgprocess created"); + process->pid =3D current->pid; + process->tgid =3D current->tgid; + ret =3D dxgvmb_send_create_process(process); + if (ret < 0) { + DXG_TRACE("send_create_process failed"); + kfree(process); + process =3D NULL; + } else { + INIT_LIST_HEAD(&process->plistentry); + kref_init(&process->process_kref); + + mutex_lock(&dxgglobal->plistmutex); + list_add_tail(&process->plistentry, + &dxgglobal->plisthead); + mutex_unlock(&dxgglobal->plistmutex); + + hmgrtable_init(&process->handle_table, process); + hmgrtable_init(&process->local_handle_table, process); + INIT_LIST_HEAD(&process->process_adapter_list_head); + } + } + return process; +} + +void dxgprocess_destroy(struct dxgprocess *process) +{ + int i; + enum hmgrentry_type t; + struct d3dkmthandle h; + void *o; + struct dxgprocess_adapter *entry; + struct dxgprocess_adapter *tmp; + + /* Destroy all adapter state */ + dxgglobal_acquire_process_adapter_lock(); + list_for_each_entry_safe(entry, tmp, + &process->process_adapter_list_head, + process_adapter_list_entry) { + dxgprocess_adapter_destroy(entry); + } + dxgglobal_release_process_adapter_lock(); + + i =3D 0; + while (hmgrtable_next_entry(&process->local_handle_table, + &i, &t, &h, &o)) { + switch (t) { + case HMGRENTRY_TYPE_DXGADAPTER: + dxgprocess_close_adapter(process, h); + break; + default: + DXG_ERR("invalid entry in handle table %d", t); + break; + } + } + + hmgrtable_destroy(&process->handle_table); + hmgrtable_destroy(&process->local_handle_table); +} + +void dxgprocess_release(struct kref *refcount) +{ + struct dxgprocess *process; + struct dxgglobal *dxgglobal =3D dxggbl(); + + process =3D container_of(refcount, struct dxgprocess, process_kref); + + mutex_lock(&dxgglobal->plistmutex); + list_del(&process->plistentry); + mutex_unlock(&dxgglobal->plistmutex); + + dxgprocess_destroy(process); + + if (process->host_handle.v) + dxgvmb_send_destroy_process(process->host_handle); + kfree(process); +} + +struct dxgprocess_adapter *dxgprocess_get_adapter_info(struct dxgprocess + *process, + struct dxgadapter + *adapter) +{ + struct dxgprocess_adapter *entry; + + list_for_each_entry(entry, &process->process_adapter_list_head, + process_adapter_list_entry) { + if (adapter =3D=3D entry->adapter) { + DXG_TRACE("Found process info %p", entry); + return entry; + } + } + return NULL; +} + +/* + * Dxgprocess takes references on dxgadapter and dxgprocess_adapter. + * + * The process_adapter lock is held. + * + */ +int dxgprocess_open_adapter(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle *h) +{ + int ret =3D 0; + struct dxgprocess_adapter *adapter_info; + struct d3dkmthandle handle; + + h->v =3D 0; + adapter_info =3D dxgprocess_get_adapter_info(process, adapter); + if (adapter_info =3D=3D NULL) { + DXG_TRACE("creating new process adapter info"); + adapter_info =3D dxgprocess_adapter_create(process, adapter); + if (adapter_info =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + } else { + adapter_info->refcount++; + } + + handle =3D hmgrtable_alloc_handle_safe(&process->local_handle_table, + adapter, HMGRENTRY_TYPE_DXGADAPTER, + true); + if (handle.v) { + *h =3D handle; + } else { + DXG_ERR("failed to create adapter handle"); + ret =3D -ENOMEM; + } + +cleanup: + + if (ret < 0) { + if (adapter_info) + dxgprocess_adapter_release(adapter_info); + } + + return ret; +} + +int dxgprocess_close_adapter(struct dxgprocess *process, + struct d3dkmthandle handle) +{ + struct dxgadapter *adapter; + struct dxgprocess_adapter *adapter_info; + int ret =3D 0; + + if (handle.v =3D=3D 0) + return 0; + + hmgrtable_lock(&process->local_handle_table, DXGLOCK_EXCL); + adapter =3D dxgprocess_get_adapter(process, handle); + if (adapter) + hmgrtable_free_handle(&process->local_handle_table, + HMGRENTRY_TYPE_DXGADAPTER, handle); + hmgrtable_unlock(&process->local_handle_table, DXGLOCK_EXCL); + + if (adapter) { + adapter_info =3D dxgprocess_get_adapter_info(process, adapter); + if (adapter_info) { + dxgglobal_acquire_process_adapter_lock(); + dxgprocess_adapter_release(adapter_info); + dxgglobal_release_process_adapter_lock(); + } else { + ret =3D -EINVAL; + } + } else { + DXG_ERR("Adapter not found %x", handle.v); + ret =3D -EINVAL; + } + + return ret; +} + +struct dxgadapter *dxgprocess_get_adapter(struct dxgprocess *process, + struct d3dkmthandle handle) +{ + struct dxgadapter *adapter; + + adapter =3D hmgrtable_get_object_by_type(&process->local_handle_table, + HMGRENTRY_TYPE_DXGADAPTER, + handle); + if (adapter =3D=3D NULL) + DXG_ERR("Adapter not found %x", handle.v); + return adapter; +} + +/* + * Gets the adapter object from the process handle table. + * The adapter object is referenced. + * The function acquired the handle table lock shared. + */ +struct dxgadapter *dxgprocess_adapter_by_handle(struct dxgprocess *process, + struct d3dkmthandle handle) +{ + struct dxgadapter *adapter; + + hmgrtable_lock(&process->local_handle_table, DXGLOCK_SHARED); + adapter =3D hmgrtable_get_object_by_type(&process->local_handle_table, + HMGRENTRY_TYPE_DXGADAPTER, + handle); + if (adapter =3D=3D NULL) + DXG_ERR("adapter_by_handle failed %x", handle.v); + else if (kref_get_unless_zero(&adapter->adapter_kref) =3D=3D 0) { + DXG_ERR("failed to acquire adapter reference"); + adapter =3D NULL; + } + hmgrtable_unlock(&process->local_handle_table, DXGLOCK_SHARED); + return adapter; +} + +void dxgprocess_ht_lock_shared_down(struct dxgprocess *process) +{ + hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); +} + +void dxgprocess_ht_lock_shared_up(struct dxgprocess *process) +{ + hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED); +} + +void dxgprocess_ht_lock_exclusive_down(struct dxgprocess *process) +{ + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); +} + +void dxgprocess_ht_lock_exclusive_up(struct dxgprocess *process) +{ + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); +} diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 6d4b8d9d8d07..0abf45d0d3f7 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -497,6 +497,87 @@ int dxgvmb_send_set_iospace_region(u64 start, u64 len) return ret; } =20 +int dxgvmb_send_create_process(struct dxgprocess *process) +{ + int ret; + struct dxgkvmb_command_createprocess *command; + struct dxgkvmb_command_createprocess_return result =3D { 0 }; + struct dxgvmbusmsg msg; + char s[WIN_MAX_PATH]; + int i; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D init_message(&msg, NULL, process, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + command_vm_to_host_init1(&command->hdr, DXGK_VMBCOMMAND_CREATEPROCESS); + command->process =3D process; + command->process_id =3D process->pid; + command->linux_process =3D 1; + s[0] =3D 0; + __get_task_comm(s, WIN_MAX_PATH, current); + for (i =3D 0; i < WIN_MAX_PATH; i++) { + command->process_name[i] =3D s[i]; + if (s[i] =3D=3D 0) + break; + } + + ret =3D dxgvmb_send_sync_msg(&dxgglobal->channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret < 0) { + DXG_ERR("create_process failed %d", ret); + } else if (result.hprocess.v =3D=3D 0) { + DXG_ERR("create_process returned 0 handle"); + ret =3D -ENOTRECOVERABLE; + } else { + process->host_handle =3D result.hprocess; + DXG_TRACE("create_process returned %x", + process->host_handle.v); + } + + dxgglobal_release_channel_lock(); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_destroy_process(struct d3dkmthandle process) +{ + int ret; + struct dxgkvmb_command_destroyprocess *command; + struct dxgvmbusmsg msg; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D init_message(&msg, NULL, NULL, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + command_vm_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_DESTROYPROCESS, + process); + ret =3D dxgvmb_send_sync_msg_ntstatus(&dxgglobal->channel, + msg.hdr, msg.size); + dxgglobal_release_channel_lock(); + +cleanup: + free_message(&msg, NULL); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + /* * Virtual GPU messages to the host */ @@ -591,3 +672,86 @@ int dxgvmb_send_get_internal_adapter_info(struct dxgad= apter *adapter) DXG_ERR("Failed to get adapter info: %d", ret); return ret; } + +int dxgvmb_send_query_adapter_info(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryadapterinfo *args) +{ + struct dxgkvmb_command_queryadapterinfo *command; + u32 cmd_size =3D sizeof(*command) + args->private_data_size - 1; + int ret; + u32 private_data_size; + void *private_data; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + ret =3D copy_from_user(command->private_data, + args->private_data, args->private_data_size); + if (ret) { + DXG_ERR("Faled to copy private data"); + ret =3D -EINVAL; + goto cleanup; + } + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_QUERYADAPTERINFO, + process->host_handle); + command->private_data_size =3D args->private_data_size; + command->query_type =3D args->type; + + if (dxgglobal->vmbus_ver >=3D DXGK_VMBUS_INTERFACE_VERSION) { + private_data =3D msg.msg; + private_data_size =3D command->private_data_size + + sizeof(struct ntstatus); + } else { + private_data =3D command->private_data; + private_data_size =3D command->private_data_size; + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + private_data, private_data_size); + if (ret < 0) + goto cleanup; + + if (dxgglobal->vmbus_ver >=3D DXGK_VMBUS_INTERFACE_VERSION) { + ret =3D ntstatus2int(*(struct ntstatus *)private_data); + if (ret < 0) + goto cleanup; + private_data =3D (char *)private_data + sizeof(struct ntstatus); + } + + switch (args->type) { + case _KMTQAITYPE_ADAPTERTYPE: + case _KMTQAITYPE_ADAPTERTYPE_RENDER: + { + struct d3dkmt_adaptertype *adapter_type =3D + (void *)private_data; + adapter_type->paravirtualized =3D 1; + adapter_type->display_supported =3D 0; + adapter_type->post_device =3D 0; + adapter_type->indirect_display_device =3D 0; + adapter_type->acg_supported =3D 0; + adapter_type->support_set_timings_from_vidpn =3D 0; + break; + } + default: + break; + } + ret =3D copy_to_user(args->private_data, private_data, + args->private_data_size); + if (ret) { + DXG_ERR("Faled to copy private data to user"); + ret =3D -EINVAL; + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 584cdd3db6c0..a805a396e083 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -14,7 +14,11 @@ #ifndef _DXGVMBUS_H #define _DXGVMBUS_H =20 +struct dxgprocess; +struct dxgadapter; + #define DXG_MAX_VM_BUS_PACKET_SIZE (1024 * 128) +#define DXG_VM_PROCESS_NAME_LENGTH 260 =20 enum dxgkvmb_commandchanneltype { DXGKVMB_VGPU_TO_HOST, @@ -169,6 +173,26 @@ struct dxgkvmb_command_setiospaceregion { u32 shared_page_gpadl; }; =20 +struct dxgkvmb_command_createprocess { + struct dxgkvmb_command_vm_to_host hdr; + void *process; + u64 process_id; + u16 process_name[DXG_VM_PROCESS_NAME_LENGTH + 1]; + u8 csrss_process:1; + u8 dwm_process:1; + u8 wow64_process:1; + u8 linux_process:1; +}; + +struct dxgkvmb_command_createprocess_return { + struct d3dkmthandle hprocess; +}; + +// The command returns ntstatus +struct dxgkvmb_command_destroyprocess { + struct dxgkvmb_command_vm_to_host hdr; +}; + struct dxgkvmb_command_openadapter { struct dxgkvmb_command_vgpu_to_host hdr; u32 vmbus_interface_version; @@ -211,4 +235,16 @@ struct dxgkvmb_command_getinternaladapterinfo_return { struct winluid host_vgpu_luid; }; =20 +struct dxgkvmb_command_queryadapterinfo { + struct dxgkvmb_command_vgpu_to_host hdr; + enum kmtqueryadapterinfotype query_type; + u32 private_data_size; + u8 private_data[1]; +}; + +struct dxgkvmb_command_queryadapterinfo_return { + struct ntstatus status; + u8 private_data[1]; +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/hmgr.c b/drivers/hv/dxgkrnl/hmgr.c new file mode 100644 index 000000000000..526b50f46d96 --- /dev/null +++ b/drivers/hv/dxgkrnl/hmgr.c @@ -0,0 +1,563 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Handle manager implementation + * + */ + +#include +#include +#include + +#include "misc.h" +#include "dxgkrnl.h" +#include "hmgr.h" + +#undef pr_fmt +#define pr_fmt(fmt) "dxgk: " fmt + +const struct d3dkmthandle zerohandle; + +/* + * Handle parameters + */ +#define HMGRHANDLE_INSTANCE_BITS 6 +#define HMGRHANDLE_INDEX_BITS 24 +#define HMGRHANDLE_UNIQUE_BITS 2 + +#define HMGRHANDLE_INSTANCE_SHIFT 0 +#define HMGRHANDLE_INDEX_SHIFT \ + (HMGRHANDLE_INSTANCE_BITS + HMGRHANDLE_INSTANCE_SHIFT) +#define HMGRHANDLE_UNIQUE_SHIFT \ + (HMGRHANDLE_INDEX_BITS + HMGRHANDLE_INDEX_SHIFT) + +#define HMGRHANDLE_INSTANCE_MASK \ + (((1 << HMGRHANDLE_INSTANCE_BITS) - 1) << HMGRHANDLE_INSTANCE_SHIFT) +#define HMGRHANDLE_INDEX_MASK \ + (((1 << HMGRHANDLE_INDEX_BITS) - 1) << HMGRHANDLE_INDEX_SHIFT) +#define HMGRHANDLE_UNIQUE_MASK \ + (((1 << HMGRHANDLE_UNIQUE_BITS) - 1) << HMGRHANDLE_UNIQUE_SHIFT) + +#define HMGRHANDLE_INSTANCE_MAX ((1 << HMGRHANDLE_INSTANCE_BITS) - 1) +#define HMGRHANDLE_INDEX_MAX ((1 << HMGRHANDLE_INDEX_BITS) - 1) +#define HMGRHANDLE_UNIQUE_MAX ((1 << HMGRHANDLE_UNIQUE_BITS) - 1) + +/* + * Handle entry + */ +struct hmgrentry { + union { + void *object; + struct { + u32 prev_free_index; + u32 next_free_index; + }; + }; + u32 type:HMGRENTRY_TYPE_BITS + 1; + u32 unique:HMGRHANDLE_UNIQUE_BITS; + u32 instance:HMGRHANDLE_INSTANCE_BITS; + u32 destroyed:1; +}; + +#define HMGRTABLE_SIZE_INCREMENT 1024 +#define HMGRTABLE_MIN_FREE_ENTRIES 128 +#define HMGRTABLE_INVALID_INDEX (~((1 << HMGRHANDLE_INDEX_BITS) - 1)) +#define HMGRTABLE_SIZE_MAX 0xFFFFFFF + +static u32 table_size_increment =3D HMGRTABLE_SIZE_INCREMENT; + +static u32 get_unique(struct d3dkmthandle h) +{ + return (h.v & HMGRHANDLE_UNIQUE_MASK) >> HMGRHANDLE_UNIQUE_SHIFT; +} + +static u32 get_index(struct d3dkmthandle h) +{ + return (h.v & HMGRHANDLE_INDEX_MASK) >> HMGRHANDLE_INDEX_SHIFT; +} + +static bool is_handle_valid(struct hmgrtable *table, struct d3dkmthandle h, + bool ignore_destroyed, enum hmgrentry_type t) +{ + u32 index =3D get_index(h); + u32 unique =3D get_unique(h); + struct hmgrentry *entry; + + if (index >=3D table->table_size) { + DXG_ERR("Invalid index %x %d", h.v, index); + return false; + } + + entry =3D &table->entry_table[index]; + if (unique !=3D entry->unique) { + DXG_ERR("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"); + return false; + } + + if (entry->type =3D=3D HMGRENTRY_TYPE_FREE) { + DXG_ERR("Entry is freed %x %d", h.v, index); + return false; + } + + if (t !=3D HMGRENTRY_TYPE_FREE && t !=3D entry->type) { + DXG_ERR("type mismatch %x %d %d", h.v, t, entry->type); + return false; + } + + return true; +} + +static struct d3dkmthandle build_handle(u32 index, u32 unique, u32 instanc= e) +{ + struct d3dkmthandle handle; + + handle.v =3D (index << HMGRHANDLE_INDEX_SHIFT) & HMGRHANDLE_INDEX_MASK; + handle.v |=3D (unique << HMGRHANDLE_UNIQUE_SHIFT) & + HMGRHANDLE_UNIQUE_MASK; + handle.v |=3D (instance << HMGRHANDLE_INSTANCE_SHIFT) & + HMGRHANDLE_INSTANCE_MASK; + + return handle; +} + +inline u32 hmgrtable_get_used_entry_count(struct hmgrtable *table) +{ + DXGKRNL_ASSERT(table->table_size >=3D table->free_count); + return (table->table_size - table->free_count); +} + +bool hmgrtable_mark_destroyed(struct hmgrtable *table, struct d3dkmthandle= h) +{ + if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE)) + return false; + + table->entry_table[get_index(h)].destroyed =3D true; + return true; +} + +bool hmgrtable_unmark_destroyed(struct hmgrtable *table, struct d3dkmthand= le h) +{ + if (!is_handle_valid(table, h, true, HMGRENTRY_TYPE_FREE)) + return true; + + DXGKRNL_ASSERT(table->entry_table[get_index(h)].destroyed); + table->entry_table[get_index(h)].destroyed =3D 0; + return true; +} + +static bool expand_table(struct hmgrtable *table, u32 NumEntries) +{ + u32 new_table_size; + struct hmgrentry *new_entry; + u32 table_index; + u32 new_free_count; + u32 prev_free_index; + u32 tail_index =3D table->free_handle_list_tail; + + /* The tail should point to the last free element in the list */ + if (table->free_count !=3D 0) { + if (tail_index >=3D table->table_size || + table->entry_table[tail_index].next_free_index !=3D + HMGRTABLE_INVALID_INDEX) { + DXG_ERR("corruption"); + DXG_ERR("tail_index: %x", tail_index); + DXG_ERR("table size: %x", table->table_size); + DXG_ERR("free_count: %d", table->free_count); + DXG_ERR("NumEntries: %x", NumEntries); + return false; + } + } + + new_free_count =3D table_size_increment + table->free_count; + new_table_size =3D table->table_size + table_size_increment; + if (new_table_size < NumEntries) { + new_free_count +=3D NumEntries - new_table_size; + new_table_size =3D NumEntries; + } + + if (new_table_size > HMGRHANDLE_INDEX_MAX) { + DXG_ERR("Invalid new table size"); + return false; + } + + new_entry =3D (struct hmgrentry *) + vzalloc(new_table_size * sizeof(struct hmgrentry)); + if (new_entry =3D=3D NULL) { + DXG_ERR("allocation failed"); + return false; + } + + if (table->entry_table) { + memcpy(new_entry, table->entry_table, + table->table_size * sizeof(struct hmgrentry)); + vfree(table->entry_table); + } else { + table->free_handle_list_head =3D 0; + } + + table->entry_table =3D new_entry; + + /* Initialize new table entries and add to the free list */ + table_index =3D table->table_size; + + prev_free_index =3D table->free_handle_list_tail; + + while (table_index < new_table_size) { + struct hmgrentry *entry =3D &table->entry_table[table_index]; + + entry->prev_free_index =3D prev_free_index; + entry->next_free_index =3D table_index + 1; + entry->type =3D HMGRENTRY_TYPE_FREE; + entry->unique =3D 1; + entry->instance =3D 0; + prev_free_index =3D table_index; + + table_index++; + } + + table->entry_table[table_index - 1].next_free_index =3D + (u32) HMGRTABLE_INVALID_INDEX; + + if (table->free_count !=3D 0) { + /* Link the current free list with the new entries */ + struct hmgrentry *entry; + + entry =3D &table->entry_table[table->free_handle_list_tail]; + entry->next_free_index =3D table->table_size; + } + table->free_handle_list_tail =3D new_table_size - 1; + if (table->free_handle_list_head =3D=3D HMGRTABLE_INVALID_INDEX) + table->free_handle_list_head =3D table->table_size; + + table->table_size =3D new_table_size; + table->free_count =3D new_free_count; + + return true; +} + +void hmgrtable_init(struct hmgrtable *table, struct dxgprocess *process) +{ + table->process =3D process; + table->entry_table =3D NULL; + table->table_size =3D 0; + table->free_handle_list_head =3D HMGRTABLE_INVALID_INDEX; + table->free_handle_list_tail =3D HMGRTABLE_INVALID_INDEX; + table->free_count =3D 0; + init_rwsem(&table->table_lock); +} + +void hmgrtable_destroy(struct hmgrtable *table) +{ + if (table->entry_table) { + vfree(table->entry_table); + table->entry_table =3D NULL; + } +} + +void hmgrtable_lock(struct hmgrtable *table, enum dxglockstate state) +{ + if (state =3D=3D DXGLOCK_EXCL) + down_write(&table->table_lock); + else + down_read(&table->table_lock); +} + +void hmgrtable_unlock(struct hmgrtable *table, enum dxglockstate state) +{ + if (state =3D=3D DXGLOCK_EXCL) + up_write(&table->table_lock); + else + up_read(&table->table_lock); +} + +struct d3dkmthandle hmgrtable_alloc_handle(struct hmgrtable *table, + void *object, + enum hmgrentry_type type, + bool make_valid) +{ + u32 index; + struct hmgrentry *entry; + u32 unique; + + DXGKRNL_ASSERT(type <=3D HMGRENTRY_TYPE_LIMIT); + DXGKRNL_ASSERT(type > HMGRENTRY_TYPE_FREE); + + if (table->free_count <=3D HMGRTABLE_MIN_FREE_ENTRIES) { + if (!expand_table(table, 0)) { + DXG_ERR("hmgrtable expand_table failed"); + return zerohandle; + } + } + + if (table->free_handle_list_head >=3D table->table_size) { + DXG_ERR("hmgrtable corrupted handle table head"); + return zerohandle; + } + + index =3D table->free_handle_list_head; + entry =3D &table->entry_table[index]; + + if (entry->type !=3D HMGRENTRY_TYPE_FREE) { + DXG_ERR("hmgrtable expected free handle"); + return zerohandle; + } + + table->free_handle_list_head =3D entry->next_free_index; + + if (entry->next_free_index !=3D table->free_handle_list_tail) { + if (entry->next_free_index >=3D table->table_size) { + DXG_ERR("hmgrtable invalid next free index"); + return zerohandle; + } + table->entry_table[entry->next_free_index].prev_free_index =3D + HMGRTABLE_INVALID_INDEX; + } + + unique =3D table->entry_table[index].unique; + + table->entry_table[index].object =3D object; + table->entry_table[index].type =3D type; + table->entry_table[index].instance =3D 0; + table->entry_table[index].destroyed =3D !make_valid; + table->free_count--; + DXGKRNL_ASSERT(table->free_count <=3D table->table_size); + + return build_handle(index, unique, table->entry_table[index].instance); +} + +int hmgrtable_assign_handle_safe(struct hmgrtable *table, + void *object, + enum hmgrentry_type type, + struct d3dkmthandle h) +{ + int ret; + + hmgrtable_lock(table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(table, object, type, h); + hmgrtable_unlock(table, DXGLOCK_EXCL); + return ret; +} + +int hmgrtable_assign_handle(struct hmgrtable *table, void *object, + enum hmgrentry_type type, struct d3dkmthandle h) +{ + u32 index =3D get_index(h); + u32 unique =3D get_unique(h); + struct hmgrentry *entry =3D NULL; + + DXG_TRACE("%x, %d %p, %p", h.v, index, object, table); + + if (index >=3D HMGRHANDLE_INDEX_MAX) { + DXG_ERR("handle index is too big: %x %d", h.v, index); + return -EINVAL; + } + + if (index >=3D table->table_size) { + u32 new_size =3D index + table_size_increment; + + if (new_size > HMGRHANDLE_INDEX_MAX) + new_size =3D HMGRHANDLE_INDEX_MAX; + if (!expand_table(table, new_size)) { + DXG_ERR("failed to expand handle table %d", + new_size); + return -ENOMEM; + } + } + + entry =3D &table->entry_table[index]; + + if (entry->type !=3D HMGRENTRY_TYPE_FREE) { + DXG_ERR("the entry is not free: %d %x", entry->type, + hmgrtable_build_entry_handle(table, index).v); + return -EINVAL; + } + + if (index !=3D table->free_handle_list_tail) { + if (entry->next_free_index >=3D table->table_size) { + DXG_ERR("hmgr: invalid next free index %d", + entry->next_free_index); + return -EINVAL; + } + table->entry_table[entry->next_free_index].prev_free_index =3D + entry->prev_free_index; + } else { + table->free_handle_list_tail =3D entry->prev_free_index; + } + + if (index !=3D table->free_handle_list_head) { + if (entry->prev_free_index >=3D table->table_size) { + DXG_ERR("hmgr: invalid next prev index %d", + entry->prev_free_index); + return -EINVAL; + } + table->entry_table[entry->prev_free_index].next_free_index =3D + entry->next_free_index; + } else { + table->free_handle_list_head =3D entry->next_free_index; + } + + entry->prev_free_index =3D HMGRTABLE_INVALID_INDEX; + entry->next_free_index =3D HMGRTABLE_INVALID_INDEX; + entry->object =3D object; + entry->type =3D type; + entry->instance =3D 0; + entry->unique =3D unique; + entry->destroyed =3D false; + + table->free_count--; + DXGKRNL_ASSERT(table->free_count <=3D table->table_size); + return 0; +} + +struct d3dkmthandle hmgrtable_alloc_handle_safe(struct hmgrtable *table, + void *obj, + enum hmgrentry_type type, + bool make_valid) +{ + struct d3dkmthandle h; + + hmgrtable_lock(table, DXGLOCK_EXCL); + h =3D hmgrtable_alloc_handle(table, obj, type, make_valid); + hmgrtable_unlock(table, DXGLOCK_EXCL); + return h; +} + +void hmgrtable_free_handle(struct hmgrtable *table, enum hmgrentry_type t, + struct d3dkmthandle h) +{ + struct hmgrentry *entry; + u32 i =3D get_index(h); + + DXG_TRACE("%p %x", table, h.v); + + /* Ignore the destroyed flag when checking the handle */ + if (is_handle_valid(table, h, true, t)) { + DXGKRNL_ASSERT(table->free_count < table->table_size); + entry =3D &table->entry_table[i]; + entry->unique =3D 1; + entry->type =3D HMGRENTRY_TYPE_FREE; + entry->destroyed =3D 0; + if (entry->unique !=3D HMGRHANDLE_UNIQUE_MAX) + entry->unique +=3D 1; + else + entry->unique =3D 1; + + table->free_count++; + DXGKRNL_ASSERT(table->free_count <=3D table->table_size); + + /* + * Insert the index to the free list at the tail. + */ + entry->next_free_index =3D HMGRTABLE_INVALID_INDEX; + entry->prev_free_index =3D table->free_handle_list_tail; + entry =3D &table->entry_table[table->free_handle_list_tail]; + entry->next_free_index =3D i; + table->free_handle_list_tail =3D i; + } else { + DXG_ERR("Invalid handle to free: %d %x", i, h.v); + } +} + +void hmgrtable_free_handle_safe(struct hmgrtable *table, enum hmgrentry_ty= pe t, + struct d3dkmthandle h) +{ + hmgrtable_lock(table, DXGLOCK_EXCL); + hmgrtable_free_handle(table, t, h); + hmgrtable_unlock(table, DXGLOCK_EXCL); +} + +struct d3dkmthandle hmgrtable_build_entry_handle(struct hmgrtable *table, + u32 index) +{ + DXGKRNL_ASSERT(index < table->table_size); + + return build_handle(index, table->entry_table[index].unique, + table->entry_table[index].instance); +} + +void *hmgrtable_get_object(struct hmgrtable *table, struct d3dkmthandle h) +{ + if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE)) + return NULL; + + return table->entry_table[get_index(h)].object; +} + +void *hmgrtable_get_object_by_type(struct hmgrtable *table, + enum hmgrentry_type type, + struct d3dkmthandle h) +{ + if (!is_handle_valid(table, h, false, type)) { + DXG_ERR("Invalid handle %x", h.v); + return NULL; + } + return table->entry_table[get_index(h)].object; +} + +void *hmgrtable_get_entry_object(struct hmgrtable *table, u32 index) +{ + DXGKRNL_ASSERT(index < table->table_size); + DXGKRNL_ASSERT(table->entry_table[index].type !=3D HMGRENTRY_TYPE_FREE); + + return table->entry_table[index].object; +} + +static enum hmgrentry_type hmgrtable_get_entry_type(struct hmgrtable *tabl= e, + u32 index) +{ + DXGKRNL_ASSERT(index < table->table_size); + return (enum hmgrentry_type)table->entry_table[index].type; +} + +enum hmgrentry_type hmgrtable_get_object_type(struct hmgrtable *table, + struct d3dkmthandle h) +{ + if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE)) + return HMGRENTRY_TYPE_FREE; + + return hmgrtable_get_entry_type(table, get_index(h)); +} + +void *hmgrtable_get_object_ignore_destroyed(struct hmgrtable *table, + struct d3dkmthandle h, + enum hmgrentry_type type) +{ + if (!is_handle_valid(table, h, true, type)) + return NULL; + return table->entry_table[get_index(h)].object; +} + +bool hmgrtable_next_entry(struct hmgrtable *tbl, + u32 *index, + enum hmgrentry_type *type, + struct d3dkmthandle *handle, + void **object) +{ + u32 i; + struct hmgrentry *entry; + + for (i =3D *index; i < tbl->table_size; i++) { + entry =3D &tbl->entry_table[i]; + if (entry->type !=3D HMGRENTRY_TYPE_FREE) { + *index =3D i + 1; + *object =3D entry->object; + *handle =3D build_handle(i, entry->unique, + entry->instance); + *type =3D entry->type; + return true; + } + } + return false; +} diff --git a/drivers/hv/dxgkrnl/hmgr.h b/drivers/hv/dxgkrnl/hmgr.h new file mode 100644 index 000000000000..23eec301137f --- /dev/null +++ b/drivers/hv/dxgkrnl/hmgr.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2022, Microsoft Corporation. + * + * Author: + * Iouri Tarassov + * + * Dxgkrnl Graphics Driver + * Handle manager definitions + * + */ + +#ifndef _HMGR_H_ +#define _HMGR_H_ + +#include "misc.h" + +struct hmgrentry; + +/* + * Handle manager table. + * + * Implementation notes: + * A list of free handles is built on top of the array of table entries. + * free_handle_list_head is the index of the first entry in the list. + * m_FreeHandleListTail is the index of an entry in the list, which is + * HMGRTABLE_MIN_FREE_ENTRIES from the head. It means that when a handle= is + * freed, the next time the handle can be re-used is after allocating + * HMGRTABLE_MIN_FREE_ENTRIES number of handles. + * Handles are allocated from the start of the list and free handles are + * inserted after the tail of the list. + * + */ +struct hmgrtable { + struct dxgprocess *process; + struct hmgrentry *entry_table; + u32 free_handle_list_head; + u32 free_handle_list_tail; + u32 table_size; + u32 free_count; + struct rw_semaphore table_lock; +}; + +/* + * Handle entry data types. + */ +#define HMGRENTRY_TYPE_BITS 5 + +enum hmgrentry_type { + HMGRENTRY_TYPE_FREE =3D 0, + HMGRENTRY_TYPE_DXGADAPTER =3D 1, + HMGRENTRY_TYPE_DXGSHAREDRESOURCE =3D 2, + HMGRENTRY_TYPE_DXGDEVICE =3D 3, + HMGRENTRY_TYPE_DXGRESOURCE =3D 4, + HMGRENTRY_TYPE_DXGALLOCATION =3D 5, + HMGRENTRY_TYPE_DXGOVERLAY =3D 6, + HMGRENTRY_TYPE_DXGCONTEXT =3D 7, + HMGRENTRY_TYPE_DXGSYNCOBJECT =3D 8, + HMGRENTRY_TYPE_DXGKEYEDMUTEX =3D 9, + HMGRENTRY_TYPE_DXGPAGINGQUEUE =3D 10, + HMGRENTRY_TYPE_DXGDEVICESYNCOBJECT =3D 11, + HMGRENTRY_TYPE_DXGPROCESS =3D 12, + HMGRENTRY_TYPE_DXGSHAREDVMOBJECT =3D 13, + HMGRENTRY_TYPE_DXGPROTECTEDSESSION =3D 14, + HMGRENTRY_TYPE_DXGHWQUEUE =3D 15, + HMGRENTRY_TYPE_DXGREMOTEBUNDLEOBJECT =3D 16, + HMGRENTRY_TYPE_DXGCOMPOSITIONSURFACEOBJECT =3D 17, + HMGRENTRY_TYPE_DXGCOMPOSITIONSURFACEPROXY =3D 18, + HMGRENTRY_TYPE_DXGTRACKEDWORKLOAD =3D 19, + HMGRENTRY_TYPE_LIMIT =3D ((1 << HMGRENTRY_TYPE_BITS) - 1), + HMGRENTRY_TYPE_MONITOREDFENCE =3D HMGRENTRY_TYPE_LIMIT + 1, +}; + +void hmgrtable_init(struct hmgrtable *tbl, struct dxgprocess *process); +void hmgrtable_destroy(struct hmgrtable *tbl); +void hmgrtable_lock(struct hmgrtable *tbl, enum dxglockstate state); +void hmgrtable_unlock(struct hmgrtable *tbl, enum dxglockstate state); +struct d3dkmthandle hmgrtable_alloc_handle(struct hmgrtable *tbl, void *ob= ject, + enum hmgrentry_type t, bool make_valid); +struct d3dkmthandle hmgrtable_alloc_handle_safe(struct hmgrtable *tbl, + void *obj, + enum hmgrentry_type t, + bool reserve); +int hmgrtable_assign_handle(struct hmgrtable *tbl, void *obj, + enum hmgrentry_type, struct d3dkmthandle h); +int hmgrtable_assign_handle_safe(struct hmgrtable *tbl, void *obj, + enum hmgrentry_type t, struct d3dkmthandle h); +void hmgrtable_free_handle(struct hmgrtable *tbl, enum hmgrentry_type t, + struct d3dkmthandle h); +void hmgrtable_free_handle_safe(struct hmgrtable *tbl, enum hmgrentry_type= t, + struct d3dkmthandle h); +struct d3dkmthandle hmgrtable_build_entry_handle(struct hmgrtable *tbl, + u32 index); +enum hmgrentry_type hmgrtable_get_object_type(struct hmgrtable *tbl, + struct d3dkmthandle h); +void *hmgrtable_get_object(struct hmgrtable *tbl, struct d3dkmthandle h); +void *hmgrtable_get_object_by_type(struct hmgrtable *tbl, enum hmgrentry_t= ype t, + struct d3dkmthandle h); +void *hmgrtable_get_object_ignore_destroyed(struct hmgrtable *tbl, + struct d3dkmthandle h, + enum hmgrentry_type t); +bool hmgrtable_mark_destroyed(struct hmgrtable *tbl, struct d3dkmthandle h= ); +bool hmgrtable_unmark_destroyed(struct hmgrtable *tbl, struct d3dkmthandle= h); +void *hmgrtable_get_entry_object(struct hmgrtable *tbl, u32 index); +bool hmgrtable_next_entry(struct hmgrtable *tbl, + u32 *start_index, + enum hmgrentry_type *type, + struct d3dkmthandle *handle, + void **object); + +#endif diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 23ecd15b0cd7..60e38d104517 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -22,3 +22,63 @@ =20 #undef pr_fmt #define pr_fmt(fmt) "dxgk: " fmt + +struct ioctl_desc { + int (*ioctl_callback)(struct dxgprocess *p, void __user *arg); + u32 ioctl; + u32 arg_size; +}; + +static struct ioctl_desc ioctls[] =3D { + +}; + +/* + * IOCTL processing + * The driver IOCTLs return + * - 0 in case of success + * - positive values, which are Windows NTSTATUS (for example, STATUS_PEND= ING). + * Positive values are success codes. + * - Linux negative error codes + */ +static int dxgk_ioctl(struct file *f, unsigned int p1, unsigned long p2) +{ + int code =3D _IOC_NR(p1); + int status; + struct dxgprocess *process; + + if (code < 1 || code >=3D ARRAY_SIZE(ioctls)) { + DXG_ERR("bad ioctl %x %x %x %x", + code, _IOC_TYPE(p1), _IOC_SIZE(p1), _IOC_DIR(p1)); + return -ENOTTY; + } + if (ioctls[code].ioctl_callback =3D=3D NULL) { + DXG_ERR("ioctl callback is NULL %x", code); + return -ENOTTY; + } + if (ioctls[code].ioctl !=3D p1) { + DXG_ERR("ioctl mismatch. Code: %x User: %x Kernel: %x", + code, p1, ioctls[code].ioctl); + return -ENOTTY; + } + process =3D (struct dxgprocess *)f->private_data; + if (process->tgid !=3D current->tgid) { + DXG_ERR("Call from a wrong process: %d %d", + process->tgid, current->tgid); + return -ENOTTY; + } + status =3D ioctls[code].ioctl_callback(process, (void *__user)p2); + return status; +} + +long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2) +{ + DXG_TRACE("compat ioctl %x", p1); + return dxgk_ioctl(f, p1, p2); +} + +long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2) +{ + DXG_TRACE("unlocked ioctl %x Code:%d", p1, _IOC_NR(p1)); + return dxgk_ioctl(f, p1, p2); +} diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h index d292e9a9bb7f..dc849a8ed3f2 100644 --- a/drivers/hv/dxgkrnl/misc.h +++ b/drivers/hv/dxgkrnl/misc.h @@ -27,10 +27,11 @@ extern const struct d3dkmthandle zerohandle; * * channel_lock (VMBus channel lock) * fd_mutex - * plistmutex (process list mutex) - * table_lock (handle table lock) - * core_lock (dxgadapter lock) - * device_lock (dxgdevice lock) + * plistmutex + * table_lock + * core_lock + * device_lock + * process_adapter_mutex * adapter_list_lock * device_mutex (dxgglobal mutex) */ diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 2ea04cc02a1f..c675d5827ed5 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -58,4 +58,107 @@ struct winluid { __u32 b; }; =20 +#define D3DKMT_ADAPTERS_MAX 64 + +struct d3dkmt_adapterinfo { + struct d3dkmthandle adapter_handle; + struct winluid adapter_luid; + __u32 num_sources; + __u32 present_move_regions_preferred; +}; + +struct d3dkmt_enumadapters2 { + __u32 num_adapters; + __u32 reserved; +#ifdef __KERNEL__ + struct d3dkmt_adapterinfo *adapters; +#else + __u64 *adapters; +#endif +}; + +struct d3dkmt_closeadapter { + struct d3dkmthandle adapter_handle; +}; + +struct d3dkmt_openadapterfromluid { + struct winluid adapter_luid; + struct d3dkmthandle adapter_handle; +}; + +struct d3dkmt_adaptertype { + union { + struct { + __u32 render_supported:1; + __u32 display_supported:1; + __u32 software_device:1; + __u32 post_device:1; + __u32 hybrid_discrete:1; + __u32 hybrid_integrated:1; + __u32 indirect_display_device:1; + __u32 paravirtualized:1; + __u32 acg_supported:1; + __u32 support_set_timings_from_vidpn:1; + __u32 detachable:1; + __u32 compute_only:1; + __u32 prototype:1; + __u32 reserved:19; + }; + __u32 value; + }; +}; + +enum kmtqueryadapterinfotype { + _KMTQAITYPE_UMDRIVERPRIVATE =3D 0, + _KMTQAITYPE_ADAPTERTYPE =3D 15, + _KMTQAITYPE_ADAPTERTYPE_RENDER =3D 57 +}; + +struct d3dkmt_queryadapterinfo { + struct d3dkmthandle adapter; + enum kmtqueryadapterinfotype type; +#ifdef __KERNEL__ + void *private_data; +#else + __u64 private_data; +#endif + __u32 private_data_size; +}; + +union d3dkmt_enumadapters_filter { + struct { + __u64 include_compute_only:1; + __u64 include_display_only:1; + __u64 reserved:62; + }; + __u64 value; +}; + +struct d3dkmt_enumadapters3 { + union d3dkmt_enumadapters_filter filter; + __u32 adapter_count; + __u32 reserved; +#ifdef __KERNEL__ + struct d3dkmt_adapterinfo *adapters; +#else + __u64 adapters; +#endif +}; + +/* + * Dxgkrnl Graphics Port Driver ioctl definitions + * + */ + +#define LX_DXOPENADAPTERFROMLUID \ + _IOWR(0x47, 0x01, struct d3dkmt_openadapterfromluid) +#define LX_DXQUERYADAPTERINFO \ + _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) +#define LX_DXENUMADAPTERS2 \ + _IOWR(0x47, 0x14, struct d3dkmt_enumadapters2) +#define LX_DXCLOSEADAPTER \ + _IOWR(0x47, 0x15, struct d3dkmt_closeadapter) +#define LX_DXENUMADAPTERS3 \ + _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) + #endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8A1A73F7E89 for ; Thu, 19 Mar 2026 20:25:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951923; cv=none; b=iMzF9BV8H+8ShQYRTVKOAr7eQwdCdGQIXs9z5lOyOGVi6Z9E3NjqJphlCPeQHVPYmciNTziamNXaYd2/tG/2MeJOJLSAlMDp4DftEMDofTu5OxRM9uqepwOfaXEIS3GMKl7oTvqcskzsj9lsqMwlC5nOYQw2fBcKs9TO/xC0Jg8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951923; c=relaxed/simple; bh=qGghHzSatalMogZ7g0RJU9cqxZSAkZm+ZhQKC+AJAtA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=u0eIDaObcIxyCqjL/aUFRNRWw6pBit61xhLMXI0VQmWx5JkcaYpfcQm6ka7uheAaTCx1ZwbC4ajr5pP3VvRZ1auZevr9Y7/i/jp/X6ft2ngHfn3+yav5aTxKbQf68VmL8dHcZKmXzE0JI9zhY5nd0XgFBZt2VjbUjEGGzEe4GRM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=bxxTcgZt; arc=none smtp.client-ip=209.85.221.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="bxxTcgZt" Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-439bc14dcf4so1709605f8f.1 for ; Thu, 19 Mar 2026 13:25:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951919; x=1774556719; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=3RvrOs3oIfDFuvp3whx4JprpZOSJFy7Rydge9ZS5yPI=; b=bxxTcgZtX3Y0+iAAeqIzz1b7En2aM2NixnGmS3ILcrrM93Hc+T/wDJO7Sn8ROJiW/f rT3uvL8LUzeGp8Mh5qRblPDt2xM6GcYd45Utg5n6hObU++cJAYTp4QCYG03SG9rG0pNw 8sYSgdzynOYVpR5YdYiDM9qQ8ABahmbgF36KPLCG6XeAmnv+q34dOw91EXctHg+KNZpf fAjwys6HQ4eBHuxeHRzKG74L0VNSI1v6CEb/YpGHG7hcJLDM7WG8G+s4LqhTF7uqxUge 7bxraZN48p2Zdnd3IfExRKAcCD28o7QPjCAVlcCimW2oWnqgmZU6+bKRKncGQRtTXG1+ EQmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951919; x=1774556719; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=3RvrOs3oIfDFuvp3whx4JprpZOSJFy7Rydge9ZS5yPI=; b=V5e3hNYhFiLJmzZEnXTByuYSp2quUmKKnyalJyb06Wph/qm8hCoja6qVAbwLXnODRa l/2TtHJx4yI6Fs8YBxOTGj9HXwgoKvSDh9UxeYEQgREptSGjVdaAV6TbDaK85zPpltao J/9aHfxOaARtZQ3FLudInazGtFWDtLR7jFOmE1Lf3RlnBMR3ug9XhVVRkhWR2nM2CBwX foHsrsGsNOV3CDcvea3pxE1a0PvRUPYxUzajkehZFaUvaSeCJHyxOxuBV/IIFITFQCVC 1HCUAUN5+NoOlzqMeXwV5lnOpkNfYK+hisNUXXaiSwsTK1KJMLPjeWzrrFplUFdwZ2X4 V/mQ== X-Gm-Message-State: AOJu0YxFkSVwV9CSwtUY4ugJ6xPSuxLeNuI1yjtQCMI5RKGdXWzt8Cl8 vES/OEIBf7sv2V4DwONfQu6PV31jZPqrAPIJ5FX1Cb+Fh02KzN3fgwNI X-Gm-Gg: ATEYQzxHevFCkRiEouPCyTV2qtBkmeiN/Wa8PjOcbJtjZHFoBVFkrdlv/supJSKqI5Z hYm+Op5RkCoSGc/mNv+ep5fYhdcVai3LnUj0wN8smT6IIx1xlyhOja7O9H9OzP+BWfnQttNulZ/ mxkMzVF+dzqDzHs1xSZXHY4jRi8YyasseoUYFuV/Y4Ket/kj/suMXUC2wxhWeQvOT9A/LfVRvOf WbSXaKGP6Ch7txiLTfhoZFGVIaLKTwdBcZMX/03xe7BQTPzfktF4sZOmfhopDs9h3F9CQ4YvLBG oLj1GSR3gffbXhYqxI7GAAlJR0B89sQXB9wbfCkcV/KdwaWtgmNxXKBJLFAA32utJPDdVafsjdl hTrCvmHxZxZPT3UjIQsrcmQXFfGXgDlzCbRVMi4a61+4oPMWvFe6VqtNIH48tEKotAPc0/iCZZK IYQVYgHN1IhKF0SJgYpKi/PGzXZRRHZOyls5+5uIyRR2e4HZN4QtkbTYN9YvI= X-Received: by 2002:a05:6000:2409:b0:439:c078:9a57 with SMTP id ffacd0b85a97d-43b6428769cmr1354629f8f.25.1773951918685; Thu, 19 Mar 2026 13:25:18 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.17 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:17 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 05/55] drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects Date: Thu, 19 Mar 2026 20:24:19 +0000 Message-ID: <20260319202509.63802-6-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls to enumerate dxgadapter objects: - The LX_DXENUMADAPTERS2 ioctl - The LX_DXENUMADAPTERS3 ioctl. Implement ioctls to open adapter by LUID and to close adapter handle: - The LX_DXOPENADAPTERFROMLUID ioctl - the LX_DXCLOSEADAPTER ioctl Impllement the ioctl to query dxgadapter information: - The LX_DXQUERYADAPTERINFO ioctl When a dxgadapter is enumerated, it is implicitely opened and a handle (d3dkmthandle) is created in the current process handle table. The handle is returned to the caller and can be used by user mode to reference the VGPU adapter in other ioctls. The caller is responsible to close the adapter when it is not longer used by sending the LX_DXCLOSEADAPTER ioctl. A dxgprocess has a list of opened dxgadapter objects (dxgprocess_adapter is used to represent the entry in the list). A dxgadapter also has a list of dxgprocess_adapter objects. This is needed for cleanup because either a process or an adapter could be destroyed first. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgmodule.c | 3 + drivers/hv/dxgkrnl/ioctl.c | 482 ++++++++++++++++++++++++++++++++- 2 files changed, 484 insertions(+), 1 deletion(-) diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 17c22001ca6c..fbe1c58ecb46 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -721,6 +721,9 @@ static struct dxgglobal *dxgglobal_create(void) =20 init_rwsem(&dxgglobal->channel_lock); =20 +#ifdef DEBUG + dxgk_validate_ioctls(); +#endif return dxgglobal; } =20 diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 60e38d104517..b08ea9430093 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -29,8 +29,472 @@ struct ioctl_desc { u32 arg_size; }; =20 -static struct ioctl_desc ioctls[] =3D { +#ifdef DEBUG +static char *errorstr(int ret) +{ + return ret < 0 ? "err" : ""; +} +#endif + +static int dxgkio_open_adapter_from_luid(struct dxgprocess *process, + void *__user inargs) +{ + struct d3dkmt_openadapterfromluid args; + int ret; + struct dxgadapter *entry; + struct dxgadapter *adapter =3D NULL; + struct d3dkmt_openadapterfromluid *__user result =3D inargs; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("Faled to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED); + dxgglobal_acquire_process_adapter_lock(); + + list_for_each_entry(entry, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (dxgadapter_acquire_lock_shared(entry) =3D=3D 0) { + if (*(u64 *) &entry->luid =3D=3D + *(u64 *) &args.adapter_luid) { + ret =3D dxgprocess_open_adapter(process, entry, + &args.adapter_handle); + + if (ret >=3D 0) { + ret =3D copy_to_user( + &result->adapter_handle, + &args.adapter_handle, + sizeof(struct d3dkmthandle)); + if (ret) + ret =3D -EINVAL; + } + adapter =3D entry; + } + dxgadapter_release_lock_shared(entry); + if (adapter) + break; + } + } + + dxgglobal_release_process_adapter_lock(); + dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED); + + if (args.adapter_handle.v =3D=3D 0) + ret =3D -EINVAL; + +cleanup: + + if (ret < 0) + dxgprocess_close_adapter(process, args.adapter_handle); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkp_enum_adapters(struct dxgprocess *process, + union d3dkmt_enumadapters_filter filter, + u32 adapter_count_max, + struct d3dkmt_adapterinfo *__user info_out, + u32 * __user adapter_count_out) +{ + int ret =3D 0; + struct dxgadapter *entry; + struct d3dkmt_adapterinfo *info =3D NULL; + struct dxgadapter **adapters =3D NULL; + int adapter_count =3D 0; + int i; + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (info_out =3D=3D NULL || adapter_count_max =3D=3D 0) { + ret =3D copy_to_user(adapter_count_out, + &dxgglobal->num_adapters, sizeof(u32)); + if (ret) { + DXG_ERR("copy_to_user faled"); + ret =3D -EINVAL; + } + goto cleanup; + } + + if (adapter_count_max > 0xFFFF) { + DXG_ERR("too many adapters"); + ret =3D -EINVAL; + goto cleanup; + } + + info =3D vzalloc(sizeof(struct d3dkmt_adapterinfo) * adapter_count_max); + if (info =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + adapters =3D vzalloc(sizeof(struct dxgadapter *) * adapter_count_max); + if (adapters =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED); + dxgglobal_acquire_process_adapter_lock(); =20 + list_for_each_entry(entry, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (dxgadapter_acquire_lock_shared(entry) =3D=3D 0) { + struct d3dkmt_adapterinfo *inf =3D &info[adapter_count]; + + ret =3D dxgprocess_open_adapter(process, entry, + &inf->adapter_handle); + if (ret >=3D 0) { + inf->adapter_luid =3D entry->luid; + adapters[adapter_count] =3D entry; + DXG_TRACE("adapter: %x %x:%x", + inf->adapter_handle.v, + inf->adapter_luid.b, + inf->adapter_luid.a); + adapter_count++; + } + dxgadapter_release_lock_shared(entry); + } + if (ret < 0) + break; + } + + dxgglobal_release_process_adapter_lock(); + dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED); + + if (adapter_count > adapter_count_max) { + ret =3D STATUS_BUFFER_TOO_SMALL; + DXG_TRACE("Too many adapters"); + ret =3D copy_to_user(adapter_count_out, + &dxgglobal->num_adapters, sizeof(u32)); + if (ret) { + DXG_ERR("copy_to_user failed"); + ret =3D -EINVAL; + } + goto cleanup; + } + + ret =3D copy_to_user(adapter_count_out, &adapter_count, + sizeof(adapter_count)); + if (ret) { + DXG_ERR("failed to copy adapter_count"); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D copy_to_user(info_out, info, sizeof(info[0]) * adapter_count); + if (ret) { + DXG_ERR("failed to copy adapter info"); + ret =3D -EINVAL; + } + +cleanup: + + if (ret >=3D 0) { + DXG_TRACE("found %d adapters", adapter_count); + goto success; + } + if (info) { + for (i =3D 0; i < adapter_count; i++) + dxgprocess_close_adapter(process, + info[i].adapter_handle); + } +success: + if (info) + vfree(info); + if (adapters) + vfree(adapters); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_enum_adapters(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_enumadapters2 args; + int ret; + struct dxgadapter *entry; + struct d3dkmt_adapterinfo *info =3D NULL; + struct dxgadapter **adapters =3D NULL; + int adapter_count =3D 0; + int i; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.adapters =3D=3D NULL) { + DXG_TRACE("buffer is NULL"); + args.num_adapters =3D dxgglobal->num_adapters; + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy args to user"); + ret =3D -EINVAL; + } + goto cleanup; + } + if (args.num_adapters < dxgglobal->num_adapters) { + args.num_adapters =3D dxgglobal->num_adapters; + DXG_TRACE("buffer is too small"); + ret =3D -EOVERFLOW; + goto cleanup; + } + + if (args.num_adapters > D3DKMT_ADAPTERS_MAX) { + DXG_TRACE("too many adapters"); + ret =3D -EINVAL; + goto cleanup; + } + + info =3D vzalloc(sizeof(struct d3dkmt_adapterinfo) * args.num_adapters); + if (info =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + adapters =3D vzalloc(sizeof(struct dxgadapter *) * args.num_adapters); + if (adapters =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED); + dxgglobal_acquire_process_adapter_lock(); + + list_for_each_entry(entry, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (dxgadapter_acquire_lock_shared(entry) =3D=3D 0) { + struct d3dkmt_adapterinfo *inf =3D &info[adapter_count]; + + ret =3D dxgprocess_open_adapter(process, entry, + &inf->adapter_handle); + if (ret >=3D 0) { + inf->adapter_luid =3D entry->luid; + adapters[adapter_count] =3D entry; + DXG_TRACE("adapter: %x %llx", + inf->adapter_handle.v, + *(u64 *) &inf->adapter_luid); + adapter_count++; + } + dxgadapter_release_lock_shared(entry); + } + if (ret < 0) + break; + } + + dxgglobal_release_process_adapter_lock(); + dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED); + + args.num_adapters =3D adapter_count; + + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy args to user"); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D copy_to_user(args.adapters, info, + sizeof(info[0]) * args.num_adapters); + if (ret) { + DXG_ERR("failed to copy adapter info to user"); + ret =3D -EINVAL; + } + +cleanup: + + if (ret < 0) { + if (info) { + for (i =3D 0; i < args.num_adapters; i++) { + dxgprocess_close_adapter(process, + info[i].adapter_handle); + } + } + } else { + DXG_TRACE("found %d adapters", args.num_adapters); + } + + if (info) + vfree(info); + if (adapters) + vfree(adapters); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_enum_adapters3(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_enumadapters3 args; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgkp_enum_adapters(process, args.filter, + args.adapter_count, + args.adapters, + &((struct d3dkmt_enumadapters3 *)inargs)-> + adapter_count); + +cleanup: + + DXG_TRACE("ioctl: %s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_close_adapter(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmthandle args; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgprocess_close_adapter(process, args); + if (ret < 0) + DXG_ERR("failed to close adapter: %d", ret); + +cleanup: + + DXG_TRACE("ioctl: %s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_query_adapter_info(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_queryadapterinfo args; + int ret; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.private_data_size > DXG_MAX_VM_BUS_PACKET_SIZE || + args.private_data_size =3D=3D 0) { + DXG_ERR("invalid private data size"); + ret =3D -EINVAL; + goto cleanup; + } + + DXG_TRACE("Type: %d Size: %x", args.type, args.private_data_size); + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) + goto cleanup; + + ret =3D dxgvmb_send_query_adapter_info(process, adapter, &args); + + dxgadapter_release_lock_shared(adapter); + +cleanup: + + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static struct ioctl_desc ioctls[] =3D { +/* 0x00 */ {}, +/* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, +/* 0x02 */ {}, +/* 0x03 */ {}, +/* 0x04 */ {}, +/* 0x05 */ {}, +/* 0x06 */ {}, +/* 0x07 */ {}, +/* 0x08 */ {}, +/* 0x09 */ {dxgkio_query_adapter_info, LX_DXQUERYADAPTERINFO}, +/* 0x0a */ {}, +/* 0x0b */ {}, +/* 0x0c */ {}, +/* 0x0d */ {}, +/* 0x0e */ {}, +/* 0x0f */ {}, +/* 0x10 */ {}, +/* 0x11 */ {}, +/* 0x12 */ {}, +/* 0x13 */ {}, +/* 0x14 */ {dxgkio_enum_adapters, LX_DXENUMADAPTERS2}, +/* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER}, +/* 0x16 */ {}, +/* 0x17 */ {}, +/* 0x18 */ {}, +/* 0x19 */ {}, +/* 0x1a */ {}, +/* 0x1b */ {}, +/* 0x1c */ {}, +/* 0x1d */ {}, +/* 0x1e */ {}, +/* 0x1f */ {}, +/* 0x20 */ {}, +/* 0x21 */ {}, +/* 0x22 */ {}, +/* 0x23 */ {}, +/* 0x24 */ {}, +/* 0x25 */ {}, +/* 0x26 */ {}, +/* 0x27 */ {}, +/* 0x28 */ {}, +/* 0x29 */ {}, +/* 0x2a */ {}, +/* 0x2b */ {}, +/* 0x2c */ {}, +/* 0x2d */ {}, +/* 0x2e */ {}, +/* 0x2f */ {}, +/* 0x30 */ {}, +/* 0x31 */ {}, +/* 0x32 */ {}, +/* 0x33 */ {}, +/* 0x34 */ {}, +/* 0x35 */ {}, +/* 0x36 */ {}, +/* 0x37 */ {}, +/* 0x38 */ {}, +/* 0x39 */ {}, +/* 0x3a */ {}, +/* 0x3b */ {}, +/* 0x3c */ {}, +/* 0x3d */ {}, +/* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3}, +/* 0x3f */ {}, +/* 0x40 */ {}, +/* 0x41 */ {}, +/* 0x42 */ {}, +/* 0x43 */ {}, +/* 0x44 */ {}, +/* 0x45 */ {}, }; =20 /* @@ -82,3 +546,19 @@ long dxgk_unlocked_ioctl(struct file *f, unsigned int p= 1, unsigned long p2) DXG_TRACE("unlocked ioctl %x Code:%d", p1, _IOC_NR(p1)); return dxgk_ioctl(f, p1, p2); } + +#ifdef DEBUG +void dxgk_validate_ioctls(void) +{ + int i; + + for (i=3D0; i < ARRAY_SIZE(ioctls); i++) + { + if (ioctls[i].ioctl && _IOC_NR(ioctls[i].ioctl) !=3D i) + { + DXG_ERR("Invalid ioctl"); + DXGKRNL_ASSERT(0); + } + } +} +#endif From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D36A3F7E87 for ; Thu, 19 Mar 2026 20:25:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951925; cv=none; b=aXqlQ/g7vsod7JHA+deyJcZnQ+TgepjbNbXSIN7q4iIoTDASNek9d1SxCDpUraYdlEqqGRfUYLc3Ll6H6EuM8PvW1XRKrr059fBhDZPtrjqJZ04GJ1kxfdkxAhgqpYH5zh8UZo5CWseNGsAHmbtC9FL+jZkj2KsWfAgY7WpEylQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951925; c=relaxed/simple; bh=BwbOvMcrpk/JeI9lLXANltPjkl3MrcAJhQ1ckdx2g+Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=T5vKOL8FCaL2IJFp13MQmaJpgsJh9NMP8Josg7oCM+N6YtRMnpCP1agx83x/66Umpet5FZlmmax2+Y6wG7W+Q67NG0tiZmEEmomsX3KXJOmpxFIAKG8WeFpVFlUjrrmlsCts/Ul5bfmS48UCdwSBSF44EBbOPOH6a/Cj3F75yqM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mJDSl3CR; arc=none smtp.client-ip=209.85.221.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mJDSl3CR" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-43b3f91a7abso759608f8f.1 for ; Thu, 19 Mar 2026 13:25:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951920; x=1774556720; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=EFYi4vEIDiWJbzjeVpI113/KGRLf22OTGV2qcIdBQXs=; b=mJDSl3CRt3w1u1fXfRjqRPXU6c1TRPM3urkvJjYo2oP/b1jMlrvWgKKKUAP540N2WS 5Bf0P1DSebRzr4TU8m3Mc3RRWykXWW4EKxz8j2dOTAtoVyFavH6EEugowITTcOR6vnbP hO7Olmd7tSBYezvd7yWtuolXaZ8lR8IO1cVF05yzETUFSxsU+yXSFUrvaBnyiogW4GXt u50/wdvZE0majc3RruOTb8cD5za1/xsgMxo5CQ1HRUjmalpQo10vZ/QQ04CU0mwLlIlC BZYL8XnCmE8vritmvsJlxuDXNPfJiJeZBGvkVXuW9AXHgpF6Ag07LUedHVpLJYXsyd0o GNPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951920; x=1774556720; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=EFYi4vEIDiWJbzjeVpI113/KGRLf22OTGV2qcIdBQXs=; b=E0h71utqxqsNab46bUE+xAd9UyxCOYxmv01uBS29RGlUR/jPOwf6r93c8aJ1zO1jmY CinXzlQysSOAfKKmTOtsp4A22plwiu0XGfeU/keQ4XWdpzDrSgdyeVZWviuEMxdAmafK C8hSG3Law3bp+DEqKpatfvq7ZpbCCcId4ce+m+ygOhd3cY0gwosNsDrTHHy/uB2Jkkod KQOdKIF6KPnNm2b725dnHdEiv59yf+F6zIGiQHsulIRWb9NnRJym09tqKj5AFcMAwMR2 fLYItgBEX05SddLAlOFCsJbCgBHgKy8lMm21aTilq/bpTDAmY9jofylosLg04PBDh/93 JIZw== X-Gm-Message-State: AOJu0YwyC+DkwNJTUXCUtoQLJ6GBX+3drfxYeULsaNb+1VEqwdl4UPzu LJWTz6OcDSJ4VcRVHX/321SjWW1BV1F4YfJ3c6B55g1i2YvAaFgOrdVJ X-Gm-Gg: ATEYQzwe/J+WVUiFftM+OZ5XtOTLyAGYbTLy6Fv0tzmB39v/NENayBKeniPZSfAmZYZ 33FYFhltIN3IMmpmPsntgAKssMD1dVKmgvARUMQ6j+wpHs0LGTbNPvpFn+lh6sTIV5H6t5vzB1U TIcFiYK5lOgYsCAemDCSo6xIW5mwqtL6rO29fxcPOBSiaA3CU6Y7DyQ4vbswLzeoEhrF+NAv3Xi AEx5vPwD+am0d5iahEZDZnfa0lQw4Qh8bIoOq1IZrISYd4YUgl7kFaN+1+xoldfjoIftTW66VmW AeThym72gQML/rPesQIqyg2oHtQtbUyn90RTn9V/QhdYC4wF8nSPh971TwFRvA2XODYyOhGMPL+ H513aWwrwtp0shddb80O1J5hp0XEo2DVMXwGLtNYad81VI3NONuo1qLqfrkp611ZeBKwaBGzDgJ WJCJqZNBi50qBK5ryF2x5VyiUkUdV4SfW057292pgDisZvX/hM9Eh8dZ01j8s= X-Received: by 2002:a05:6000:2f84:b0:43b:4d2e:a004 with SMTP id ffacd0b85a97d-43b64242f00mr1145615f8f.10.1773951920229; Thu, 19 Mar 2026 13:25:20 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.18 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:19 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 06/55] drivers: hv: dxgkrnl: Creation of dxgdevice objects Date: Thu, 19 Mar 2026 20:24:20 +0000 Message-ID: <20260319202509.63802-7-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls for creation and destruction of dxgdevice objects: - the LX_DXCREATEDEVICE ioctl - the LX_DXDESTROYDEVICE ioctl A dxgdevice object represents a container of other virtual compute device objects (allocations, sync objects, contexts, etc.). It belongs to a dxgadapter object. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 187 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 58 ++++++++++ drivers/hv/dxgkrnl/dxgprocess.c | 43 ++++++++ drivers/hv/dxgkrnl/dxgvmbus.c | 80 ++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 22 ++++ drivers/hv/dxgkrnl/ioctl.c | 130 +++++++++++++++++++++- drivers/hv/dxgkrnl/misc.h | 8 +- include/uapi/misc/d3dkmthk.h | 82 ++++++++++++++ 8 files changed, 604 insertions(+), 6 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index fa0d6beca157..a9a341716eba 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -194,6 +194,122 @@ void dxgadapter_release_lock_shared(struct dxgadapter= *adapter) up_read(&adapter->core_lock); } =20 +struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter, + struct dxgprocess *process) +{ + struct dxgdevice *device; + int ret; + + device =3D kzalloc(sizeof(struct dxgdevice), GFP_KERNEL); + if (device) { + kref_init(&device->device_kref); + device->adapter =3D adapter; + device->process =3D process; + kref_get(&adapter->adapter_kref); + init_rwsem(&device->device_lock); + INIT_LIST_HEAD(&device->pqueue_list_head); + device->object_state =3D DXGOBJECTSTATE_CREATED; + device->execution_state =3D _D3DKMT_DEVICEEXECUTION_ACTIVE; + + ret =3D dxgprocess_adapter_add_device(process, adapter, device); + if (ret < 0) { + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + } + } + return device; +} + +void dxgdevice_stop(struct dxgdevice *device) +{ +} + +void dxgdevice_mark_destroyed(struct dxgdevice *device) +{ + down_write(&device->device_lock); + device->object_state =3D DXGOBJECTSTATE_DESTROYED; + up_write(&device->device_lock); +} + +void dxgdevice_destroy(struct dxgdevice *device) +{ + struct dxgprocess *process =3D device->process; + struct dxgadapter *adapter =3D device->adapter; + struct d3dkmthandle device_handle =3D {}; + + DXG_TRACE("Destroying device: %p", device); + + down_write(&device->device_lock); + + if (device->object_state !=3D DXGOBJECTSTATE_ACTIVE) + goto cleanup; + + device->object_state =3D DXGOBJECTSTATE_DESTROYED; + + dxgdevice_stop(device); + + /* Guest handles need to be released before the host handles */ + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + if (device->handle_valid) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGDEVICE, device->handle); + device_handle =3D device->handle; + device->handle_valid =3D 0; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (device_handle.v) { + up_write(&device->device_lock); + if (dxgadapter_acquire_lock_shared(adapter) =3D=3D 0) { + dxgvmb_send_destroy_device(adapter, process, + device_handle); + dxgadapter_release_lock_shared(adapter); + } + down_write(&device->device_lock); + } + +cleanup: + + if (device->adapter) { + dxgprocess_adapter_remove_device(device); + kref_put(&device->adapter->adapter_kref, dxgadapter_release); + device->adapter =3D NULL; + } + + up_write(&device->device_lock); + + kref_put(&device->device_kref, dxgdevice_release); + DXG_TRACE("Device destroyed"); +} + +int dxgdevice_acquire_lock_shared(struct dxgdevice *device) +{ + down_read(&device->device_lock); + if (!dxgdevice_is_active(device)) { + up_read(&device->device_lock); + return -ENODEV; + } + return 0; +} + +void dxgdevice_release_lock_shared(struct dxgdevice *device) +{ + up_read(&device->device_lock); +} + +bool dxgdevice_is_active(struct dxgdevice *device) +{ + return device->object_state =3D=3D DXGOBJECTSTATE_ACTIVE; +} + +void dxgdevice_release(struct kref *refcount) +{ + struct dxgdevice *device; + + device =3D container_of(refcount, struct dxgdevice, device_kref); + kfree(device); +} + struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *pr= ocess, struct dxgadapter *adapter) { @@ -208,6 +324,8 @@ struct dxgprocess_adapter *dxgprocess_adapter_create(st= ruct dxgprocess *process, adapter_info->adapter =3D adapter; adapter_info->process =3D process; adapter_info->refcount =3D 1; + mutex_init(&adapter_info->device_list_mutex); + INIT_LIST_HEAD(&adapter_info->device_list_head); list_add_tail(&adapter_info->process_adapter_list_entry, &process->process_adapter_list_head); dxgadapter_add_process(adapter, adapter_info); @@ -221,10 +339,34 @@ struct dxgprocess_adapter *dxgprocess_adapter_create(= struct dxgprocess *process, =20 void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info) { + struct dxgdevice *device; + + mutex_lock(&adapter_info->device_list_mutex); + list_for_each_entry(device, &adapter_info->device_list_head, + device_list_entry) { + dxgdevice_stop(device); + } + mutex_unlock(&adapter_info->device_list_mutex); } =20 void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info) { + struct dxgdevice *device; + + mutex_lock(&adapter_info->device_list_mutex); + while (!list_empty(&adapter_info->device_list_head)) { + device =3D list_first_entry(&adapter_info->device_list_head, + struct dxgdevice, device_list_entry); + list_del(&device->device_list_entry); + device->device_list_entry.next =3D NULL; + mutex_unlock(&adapter_info->device_list_mutex); + dxgvmb_send_flush_device(device, + DXGDEVICE_FLUSHSCHEDULER_DEVICE_TERMINATE); + dxgdevice_destroy(device); + mutex_lock(&adapter_info->device_list_mutex); + } + mutex_unlock(&adapter_info->device_list_mutex); + dxgadapter_remove_process(adapter_info); kref_put(&adapter_info->adapter->adapter_kref, dxgadapter_release); list_del(&adapter_info->process_adapter_list_entry); @@ -240,3 +382,48 @@ void dxgprocess_adapter_release(struct dxgprocess_adap= ter *adapter_info) if (adapter_info->refcount =3D=3D 0) dxgprocess_adapter_destroy(adapter_info); } + +int dxgprocess_adapter_add_device(struct dxgprocess *process, + struct dxgadapter *adapter, + struct dxgdevice *device) +{ + struct dxgprocess_adapter *entry; + struct dxgprocess_adapter *adapter_info =3D NULL; + int ret =3D 0; + + dxgglobal_acquire_process_adapter_lock(); + + list_for_each_entry(entry, &process->process_adapter_list_head, + process_adapter_list_entry) { + if (entry->adapter =3D=3D adapter) { + adapter_info =3D entry; + break; + } + } + if (adapter_info =3D=3D NULL) { + DXG_ERR("failed to find process adapter info"); + ret =3D -EINVAL; + goto cleanup; + } + mutex_lock(&adapter_info->device_list_mutex); + list_add_tail(&device->device_list_entry, + &adapter_info->device_list_head); + device->adapter_info =3D adapter_info; + mutex_unlock(&adapter_info->device_list_mutex); + +cleanup: + + dxgglobal_release_process_adapter_lock(); + return ret; +} + +void dxgprocess_adapter_remove_device(struct dxgdevice *device) +{ + DXG_TRACE("Removing device: %p", device); + mutex_lock(&device->adapter_info->device_list_mutex); + if (device->device_list_entry.next) { + list_del(&device->device_list_entry); + device->device_list_entry.next =3D NULL; + } + mutex_unlock(&device->adapter_info->device_list_mutex); +} diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index b089d126f801..45ac1f25cc5e 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -34,6 +34,7 @@ =20 struct dxgprocess; struct dxgadapter; +struct dxgdevice; =20 /* * Driver private data. @@ -71,6 +72,10 @@ struct dxgk_device_types { u32 virtual_monitor_device:1; }; =20 +enum dxgdevice_flushschedulerreason { + DXGDEVICE_FLUSHSCHEDULER_DEVICE_TERMINATE =3D 4, +}; + enum dxgobjectstate { DXGOBJECTSTATE_CREATED, DXGOBJECTSTATE_ACTIVE, @@ -166,6 +171,9 @@ struct dxgprocess_adapter { struct list_head adapter_process_list_entry; /* Entry in dxgprocess::process_adapter_list_head */ struct list_head process_adapter_list_entry; + /* List of all dxgdevice objects created for the process on adapter */ + struct list_head device_list_head; + struct mutex device_list_mutex; struct dxgadapter *adapter; struct dxgprocess *process; int refcount; @@ -175,6 +183,10 @@ struct dxgprocess_adapter *dxgprocess_adapter_create(s= truct dxgprocess *process, struct dxgadapter *adapter); void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter); +int dxgprocess_adapter_add_device(struct dxgprocess *process, + struct dxgadapter *adapter, + struct dxgdevice *device); +void dxgprocess_adapter_remove_device(struct dxgdevice *device); void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info); void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info); =20 @@ -222,6 +234,11 @@ struct dxgadapter *dxgprocess_get_adapter(struct dxgpr= ocess *process, struct d3dkmthandle handle); struct dxgadapter *dxgprocess_adapter_by_handle(struct dxgprocess *process, struct d3dkmthandle handle); +struct dxgdevice *dxgprocess_device_by_handle(struct dxgprocess *process, + struct d3dkmthandle handle); +struct dxgdevice *dxgprocess_device_by_object_handle(struct dxgprocess *pr= ocess, + enum hmgrentry_type t, + struct d3dkmthandle h); void dxgprocess_ht_lock_shared_down(struct dxgprocess *process); void dxgprocess_ht_lock_shared_up(struct dxgprocess *process); void dxgprocess_ht_lock_exclusive_down(struct dxgprocess *process); @@ -241,6 +258,7 @@ enum dxgadapter_state { * This object represents the grapchis adapter. * Objects, which take reference on the adapter: * - dxgglobal + * - dxgdevice * - adapter handle (struct d3dkmthandle) */ struct dxgadapter { @@ -277,6 +295,38 @@ void dxgadapter_add_process(struct dxgadapter *adapter, struct dxgprocess_adapter *process_info); void dxgadapter_remove_process(struct dxgprocess_adapter *process_info); =20 +/* + * The object represent the device object. + * The following objects take reference on the device + * - device handle (struct d3dkmthandle) + */ +struct dxgdevice { + enum dxgobjectstate object_state; + /* Device takes reference on the adapter */ + struct dxgadapter *adapter; + struct dxgprocess_adapter *adapter_info; + struct dxgprocess *process; + /* Entry in the DGXPROCESS_ADAPTER device list */ + struct list_head device_list_entry; + struct kref device_kref; + /* Protects destcruction of the device object */ + struct rw_semaphore device_lock; + /* List of paging queues. Protected by process handle table lock. */ + struct list_head pqueue_list_head; + struct d3dkmthandle handle; + enum d3dkmt_deviceexecution_state execution_state; + u32 handle_valid; +}; + +struct dxgdevice *dxgdevice_create(struct dxgadapter *a, struct dxgprocess= *p); +void dxgdevice_destroy(struct dxgdevice *device); +void dxgdevice_stop(struct dxgdevice *device); +void dxgdevice_mark_destroyed(struct dxgdevice *device); +int dxgdevice_acquire_lock_shared(struct dxgdevice *dev); +void dxgdevice_release_lock_shared(struct dxgdevice *dev); +void dxgdevice_release(struct kref *refcount); +bool dxgdevice_is_active(struct dxgdevice *dev); + long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2); long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2= ); =20 @@ -313,6 +363,14 @@ int dxgvmb_send_destroy_process(struct d3dkmthandle pr= ocess); int dxgvmb_send_open_adapter(struct dxgadapter *adapter); int dxgvmb_send_close_adapter(struct dxgadapter *adapter); int dxgvmb_send_get_internal_adapter_info(struct dxgadapter *adapter); +struct d3dkmthandle dxgvmb_send_create_device(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmt_createdevice *args); +int dxgvmb_send_destroy_device(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmthandle h); +int dxgvmb_send_flush_device(struct dxgdevice *device, + enum dxgdevice_flushschedulerreason reason); int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.c index ab9a01e3c8c8..8373f681e822 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -241,6 +241,49 @@ struct dxgadapter *dxgprocess_adapter_by_handle(struct= dxgprocess *process, return adapter; } =20 +struct dxgdevice *dxgprocess_device_by_object_handle(struct dxgprocess *pr= ocess, + enum hmgrentry_type t, + struct d3dkmthandle handle) +{ + struct dxgdevice *device =3D NULL; + void *obj; + + hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); + obj =3D hmgrtable_get_object_by_type(&process->handle_table, t, handle); + if (obj) { + struct d3dkmthandle device_handle =3D {}; + + switch (t) { + case HMGRENTRY_TYPE_DXGDEVICE: + device =3D obj; + break; + default: + DXG_ERR("invalid handle type: %d", t); + break; + } + if (device =3D=3D NULL) + device =3D hmgrtable_get_object_by_type( + &process->handle_table, + HMGRENTRY_TYPE_DXGDEVICE, + device_handle); + if (device) + if (kref_get_unless_zero(&device->device_kref) =3D=3D 0) + device =3D NULL; + } + if (device =3D=3D NULL) + DXG_ERR("device_by_handle failed: %d %x", t, handle.v); + hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED); + return device; +} + +struct dxgdevice *dxgprocess_device_by_handle(struct dxgprocess *process, + struct d3dkmthandle handle) +{ + return dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGDEVICE, + handle); +} + void dxgprocess_ht_lock_shared_down(struct dxgprocess *process) { hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 0abf45d0d3f7..73804d11ec49 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -673,6 +673,86 @@ int dxgvmb_send_get_internal_adapter_info(struct dxgad= apter *adapter) return ret; } =20 +struct d3dkmthandle dxgvmb_send_create_device(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmt_createdevice *args) +{ + int ret; + struct dxgkvmb_command_createdevice *command; + struct dxgkvmb_command_createdevice_return result =3D { }; + struct dxgvmbusmsg msg; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_CREATEDEVICE, + process->host_handle); + command->flags =3D args->flags; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret < 0) + result.device.v =3D 0; + free_message(&msg, process); +cleanup: + if (ret) + DXG_TRACE("err: %d", ret); + return result.device; +} + +int dxgvmb_send_destroy_device(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmthandle h) +{ + int ret; + struct dxgkvmb_command_destroydevice *command; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_DESTROYDEVICE, + process->host_handle); + command->device =3D h; + + ret =3D 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_flush_device(struct dxgdevice *device, + enum dxgdevice_flushschedulerreason reason) +{ + int ret; + struct dxgkvmb_command_flushdevice *command; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + struct dxgprocess *process =3D device->process; + + ret =3D init_message(&msg, device->adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_FLUSHDEVICE, + process->host_handle); + command->device =3D device->handle; + command->reason =3D reason; + + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index a805a396e083..4ccf45765954 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -247,4 +247,26 @@ struct dxgkvmb_command_queryadapterinfo_return { u8 private_data[1]; }; =20 +struct dxgkvmb_command_createdevice { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_createdeviceflags flags; + bool cdd_device; + void *error_code; +}; + +struct dxgkvmb_command_createdevice_return { + struct d3dkmthandle device; +}; + +struct dxgkvmb_command_destroydevice { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; +}; + +struct dxgkvmb_command_flushdevice { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + enum dxgdevice_flushschedulerreason reason; +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index b08ea9430093..405e8b92913e 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -424,10 +424,136 @@ dxgkio_query_adapter_info(struct dxgprocess *process= , void *__user inargs) return ret; } =20 +static int +dxgkio_create_device(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_createdevice args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + struct d3dkmthandle host_device_handle =3D {}; + bool adapter_locked =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + /* The call acquires reference on the adapter */ + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgdevice_create(adapter, process); + if (device =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) + goto cleanup; + + adapter_locked =3D true; + + host_device_handle =3D dxgvmb_send_create_device(adapter, process, &args); + if (host_device_handle.v) { + ret =3D copy_to_user(&((struct d3dkmt_createdevice *)inargs)-> + device, &host_device_handle, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy device handle"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(&process->handle_table, device, + HMGRENTRY_TYPE_DXGDEVICE, + host_device_handle); + if (ret >=3D 0) { + device->handle =3D host_device_handle; + device->handle_valid =3D 1; + device->object_state =3D DXGOBJECTSTATE_ACTIVE; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + } + +cleanup: + + if (ret < 0) { + if (host_device_handle.v) + dxgvmb_send_destroy_device(adapter, process, + host_device_handle); + if (device) + dxgdevice_destroy(device); + } + + if (adapter_locked) + dxgadapter_release_lock_shared(adapter); + + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_destroy_device(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_destroydevice args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + device =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGDEVICE, + args.device); + if (device) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGDEVICE, args.device); + device->handle_valid =3D 0; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (device =3D=3D NULL) { + DXG_ERR("invalid device handle: %x", args.device.v); + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + + dxgdevice_destroy(device); + + if (dxgadapter_acquire_lock_shared(adapter) =3D=3D 0) { + dxgvmb_send_destroy_device(adapter, process, args.device); + dxgadapter_release_lock_shared(adapter); + } + +cleanup: + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static struct ioctl_desc ioctls[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, -/* 0x02 */ {}, +/* 0x02 */ {dxgkio_create_device, LX_DXCREATEDEVICE}, /* 0x03 */ {}, /* 0x04 */ {}, /* 0x05 */ {}, @@ -450,7 +576,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x16 */ {}, /* 0x17 */ {}, /* 0x18 */ {}, -/* 0x19 */ {}, +/* 0x19 */ {dxgkio_destroy_device, LX_DXDESTROYDEVICE}, /* 0x1a */ {}, /* 0x1b */ {}, /* 0x1c */ {}, diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h index dc849a8ed3f2..e0bd33b365b0 100644 --- a/drivers/hv/dxgkrnl/misc.h +++ b/drivers/hv/dxgkrnl/misc.h @@ -27,10 +27,10 @@ extern const struct d3dkmthandle zerohandle; * * channel_lock (VMBus channel lock) * fd_mutex - * plistmutex - * table_lock - * core_lock - * device_lock + * plistmutex (process list mutex) + * table_lock (handle table lock) + * core_lock (dxgadapter lock) + * device_lock (dxgdevice lock) * process_adapter_mutex * adapter_list_lock * device_mutex (dxgglobal mutex) diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index c675d5827ed5..7414f0f5ce8e 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -86,6 +86,74 @@ struct d3dkmt_openadapterfromluid { struct d3dkmthandle adapter_handle; }; =20 +struct d3dddi_allocationlist { + struct d3dkmthandle allocation; + union { + struct { + __u32 write_operation :1; + __u32 do_not_retire_instance :1; + __u32 offer_priority :3; + __u32 reserved :27; + }; + __u32 value; + }; +}; + +struct d3dddi_patchlocationlist { + __u32 allocation_index; + union { + struct { + __u32 slot_id:24; + __u32 reserved:8; + }; + __u32 value; + }; + __u32 driver_id; + __u32 allocation_offset; + __u32 patch_offset; + __u32 split_offset; +}; + +struct d3dkmt_createdeviceflags { + __u32 legacy_mode:1; + __u32 request_vSync:1; + __u32 disable_gpu_timeout:1; + __u32 gdi_device:1; + __u32 reserved:28; +}; + +struct d3dkmt_createdevice { + struct d3dkmthandle adapter; + __u32 reserved3; + struct d3dkmt_createdeviceflags flags; + struct d3dkmthandle device; +#ifdef __KERNEL__ + void *command_buffer; +#else + __u64 command_buffer; +#endif + __u32 command_buffer_size; + __u32 reserved; +#ifdef __KERNEL__ + struct d3dddi_allocationlist *allocation_list; +#else + __u64 allocation_list; +#endif + __u32 allocation_list_size; + __u32 reserved1; +#ifdef __KERNEL__ + struct d3dddi_patchlocationlist *patch_location_list; +#else + __u64 patch_location_list; +#endif + __u32 patch_location_list_size; + __u32 reserved2; +}; + +struct d3dkmt_destroydevice { + struct d3dkmthandle device; +}; + struct d3dkmt_adaptertype { union { struct { @@ -125,6 +193,16 @@ struct d3dkmt_queryadapterinfo { __u32 private_data_size; }; =20 +enum d3dkmt_deviceexecution_state { + _D3DKMT_DEVICEEXECUTION_ACTIVE =3D 1, + _D3DKMT_DEVICEEXECUTION_RESET =3D 2, + _D3DKMT_DEVICEEXECUTION_HUNG =3D 3, + _D3DKMT_DEVICEEXECUTION_STOPPED =3D 4, + _D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY =3D 5, + _D3DKMT_DEVICEEXECUTION_ERROR_DMAFAULT =3D 6, + _D3DKMT_DEVICEEXECUTION_ERROR_DMAPAGEFAULT =3D 7, +}; + union d3dkmt_enumadapters_filter { struct { __u64 include_compute_only:1; @@ -152,12 +230,16 @@ struct d3dkmt_enumadapters3 { =20 #define LX_DXOPENADAPTERFROMLUID \ _IOWR(0x47, 0x01, struct d3dkmt_openadapterfromluid) +#define LX_DXCREATEDEVICE \ + _IOWR(0x47, 0x02, struct d3dkmt_createdevice) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) #define LX_DXENUMADAPTERS2 \ _IOWR(0x47, 0x14, struct d3dkmt_enumadapters2) #define LX_DXCLOSEADAPTER \ _IOWR(0x47, 0x15, struct d3dkmt_closeadapter) +#define LX_DXDESTROYDEVICE \ + _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) #define LX_DXENUMADAPTERS3 \ _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2C7B63F7E9B for ; Thu, 19 Mar 2026 20:25:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951926; cv=none; b=teH0RekLkHm26J/7JhnSy3Nl9SOLjcY5OVnkkePaH9zIVtpTcDoYa+2IAi2P50qlrm3GaG74ldL0kgOnMYL7CDGoDSDemaquS9YvzfJSVJxGCSSucnqGe1qG4+XI8M7u1eNLYylN+pxVKZYzYM52eRYgaedGwn6nVUOV7VKz5Rg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951926; c=relaxed/simple; bh=6m9Fl64FQgYRCmM/OBqroPX57hoWtFkTtimspki1Gv0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OvJ8/8HyUiM/3UDOe3LW7TE2b1/kjwCnDfGJPTSNIlIvjEHyzOCEredJLHGmZdJnCR5bbPenzkhc/y2qMRhXBJY9Tgq83AYyALvFoz7pGuJfelis0hK4eDmEz03JMIMW97tP0Adc+7f1MKOe96P6fPYLI6zThYO/ZdgVUuHErOI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jgPDMX4H; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jgPDMX4H" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-48334ee0aeaso11777415e9.1 for ; Thu, 19 Mar 2026 13:25:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951921; x=1774556721; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Ows384rFvcW/0zTyYeLYh2R71jyN2NXXSfsnbCfkYBk=; b=jgPDMX4H12WC8AkpwT3EfwMmj9cbcVVv2WoLqI/60vBXsxHPTR+soE37O/jg5te23C AX2Dble5gWPrYzb9eCjRybdkhKG9TfhtwycvsCXkf6wyDNkRCt0/xrSPXDo8l2c5JfPO 1MH4aBIC5ztso5DixCBpDjlQdLrOC8U85pGTh/9TtIemXE/DM6D9yzIe+NY364Syq/RW z+3j2LSGStiMsnQOT5pzzLWQq8myJtxpMjFwsjNS1XOBEG1ZSETNlHqjiBcWqId1vYFc /hLxaOKurFwt7BdqM4txDD2DXCSqV3KzorNJX0xjBFUZ5P9jM5qGKX91Um5zN44HSULL dwqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951921; x=1774556721; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Ows384rFvcW/0zTyYeLYh2R71jyN2NXXSfsnbCfkYBk=; b=SdJAxE+CfGdjo83IuulyWKWYRjZ+AEf1N0Mj9eTi5q++c1+p5W+D8JKpwrV3JmZ+De JAtp0Z562p6hbKznVJz8uBoS5xJ1GWhiozssrKE74wpRNldgEzjePsKkYpB16Nhs7Qxl zksR2wSqQ9heMgskU5YLe31B6+0+CANMmjGgtWo+0Eib5QkqySX8hRIh77nxKbBcsIkn c+qTtq1AUZ0ZEbjRJqKlvhzTnPUcT1mfPedHLA4bqpAUC+XixQg1t/l87BC3ZZ2gkDcu VSxA2nQ7p/XnTbQvdCEAiU4V+QjjkNfkiJ/iiCmDAylUt+0VLOKm/RaUfKm5RT3OCGrG 2zEQ== X-Gm-Message-State: AOJu0YwM9RGwldg767TNueceIxvwjBQ+vqgzgG1giiyL3if1vyQaJjSZ oCXpnjnoWEN88fzIIupBkh0xU448k+3jyFtA304mmL1QWRaMkJX0C2Py X-Gm-Gg: ATEYQzy9biquavZgDr1PYYRZA6wiL67SYEN59USKLIm85ucnzmySmlpBzGGZi2G9Xf1 JahKncQP/y0j1k0KcFjnda8CwLE3C1h5SpNiKijS0awBkg0qVULA7qBIikNjUaebMQvjlzh8CRH hl7ZcaWKg+irmLHagTaPK5Qqgp2zQ/ofp4BugO7Px2mkMfKBMIJQoy8iV1hpDHN/YXdnKiKEizZ OxzB29q4I6dcINjzQ0jGwdT3tpi4DxvRRG+WG0fdvDXwlkIcvVzerhUt3bK+yJwwOfafd3yNtCf Lnez7cRpW2ou/p4renBlg3dGrGhnNC/Ac8EZVnPg0jaOLZ70cGhrJbw0K6cD1VV0iaoadqDbzf9 k4KYdR6ZEoUD/UjQDF2610sZ+Pu4dBCqhnxalV7pvg7tkvsb4yvrtNFFUVO4gLzzuAoyPin2cZQ ui208pCGQLH0j8FQH47eLTqCElCgn2mmEKyx5H5Uxcv4Ob6DAE X-Received: by 2002:a05:600c:19d4:b0:485:4278:24f0 with SMTP id 5b1f17b1804b1-486ff03d9d4mr6356905e9.30.1773951921361; Thu, 19 Mar 2026 13:25:21 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.20 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:20 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 07/55] drivers: hv: dxgkrnl: Creation of dxgcontext objects Date: Thu, 19 Mar 2026 20:24:21 +0000 Message-ID: <20260319202509.63802-8-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls for creation/destruction of dxgcontext objects: - the LX_DXCREATECONTEXTVIRTUAL ioctl - the LX_DXDESTROYCONTEXT ioctl. A dxgcontext object represents a compute device execution thread. Ccompute device DMA buffers and synchronization operations are submitted for execution to a dxgcontext. dxgcontexts objects belong to a dxgdevice object. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 103 ++++++++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 38 ++++++++ drivers/hv/dxgkrnl/dxgprocess.c | 4 + drivers/hv/dxgkrnl/dxgvmbus.c | 101 ++++++++++++++++++- drivers/hv/dxgkrnl/dxgvmbus.h | 18 ++++ drivers/hv/dxgkrnl/ioctl.c | 168 +++++++++++++++++++++++++++++++- drivers/hv/dxgkrnl/misc.h | 1 + include/uapi/misc/d3dkmthk.h | 47 +++++++++ 8 files changed, 477 insertions(+), 3 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index a9a341716eba..cd103e092ac2 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -206,7 +206,9 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *a= dapter, device->adapter =3D adapter; device->process =3D process; kref_get(&adapter->adapter_kref); + INIT_LIST_HEAD(&device->context_list_head); init_rwsem(&device->device_lock); + init_rwsem(&device->context_list_lock); INIT_LIST_HEAD(&device->pqueue_list_head); device->object_state =3D DXGOBJECTSTATE_CREATED; device->execution_state =3D _D3DKMT_DEVICEEXECUTION_ACTIVE; @@ -248,6 +250,20 @@ void dxgdevice_destroy(struct dxgdevice *device) =20 dxgdevice_stop(device); =20 + { + struct dxgcontext *context; + struct dxgcontext *tmp; + + DXG_TRACE("destroying contexts"); + dxgdevice_acquire_context_list_lock(device); + list_for_each_entry_safe(context, tmp, + &device->context_list_head, + context_list_entry) { + dxgcontext_destroy(process, context); + } + dxgdevice_release_context_list_lock(device); + } + /* Guest handles need to be released before the host handles */ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); if (device->handle_valid) { @@ -302,6 +318,32 @@ bool dxgdevice_is_active(struct dxgdevice *device) return device->object_state =3D=3D DXGOBJECTSTATE_ACTIVE; } =20 +void dxgdevice_acquire_context_list_lock(struct dxgdevice *device) +{ + down_write(&device->context_list_lock); +} + +void dxgdevice_release_context_list_lock(struct dxgdevice *device) +{ + up_write(&device->context_list_lock); +} + +void dxgdevice_add_context(struct dxgdevice *device, struct dxgcontext *co= ntext) +{ + down_write(&device->context_list_lock); + list_add_tail(&context->context_list_entry, &device->context_list_head); + up_write(&device->context_list_lock); +} + +void dxgdevice_remove_context(struct dxgdevice *device, + struct dxgcontext *context) +{ + if (context->context_list_entry.next) { + list_del(&context->context_list_entry); + context->context_list_entry.next =3D NULL; + } +} + void dxgdevice_release(struct kref *refcount) { struct dxgdevice *device; @@ -310,6 +352,67 @@ void dxgdevice_release(struct kref *refcount) kfree(device); } =20 +struct dxgcontext *dxgcontext_create(struct dxgdevice *device) +{ + struct dxgcontext *context; + + context =3D kzalloc(sizeof(struct dxgcontext), GFP_KERNEL); + if (context) { + kref_init(&context->context_kref); + context->device =3D device; + context->process =3D device->process; + context->device_handle =3D device->handle; + kref_get(&device->device_kref); + INIT_LIST_HEAD(&context->hwqueue_list_head); + init_rwsem(&context->hwqueue_list_lock); + dxgdevice_add_context(device, context); + context->object_state =3D DXGOBJECTSTATE_ACTIVE; + } + return context; +} + +/* + * Called when the device context list lock is held + */ +void dxgcontext_destroy(struct dxgprocess *process, struct dxgcontext *con= text) +{ + DXG_TRACE("Destroying context %p", context); + context->object_state =3D DXGOBJECTSTATE_DESTROYED; + if (context->device) { + if (context->handle.v) { + hmgrtable_free_handle_safe(&process->handle_table, + HMGRENTRY_TYPE_DXGCONTEXT, + context->handle); + } + dxgdevice_remove_context(context->device, context); + kref_put(&context->device->device_kref, dxgdevice_release); + } + kref_put(&context->context_kref, dxgcontext_release); +} + +void dxgcontext_destroy_safe(struct dxgprocess *process, + struct dxgcontext *context) +{ + struct dxgdevice *device =3D context->device; + + dxgdevice_acquire_context_list_lock(device); + dxgcontext_destroy(process, context); + dxgdevice_release_context_list_lock(device); +} + +bool dxgcontext_is_active(struct dxgcontext *context) +{ + return context->object_state =3D=3D DXGOBJECTSTATE_ACTIVE; +} + +void dxgcontext_release(struct kref *refcount) +{ + struct dxgcontext *context; + + context =3D container_of(refcount, struct dxgcontext, context_kref); + kfree(context); +} + struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *pr= ocess, struct dxgadapter *adapter) { diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 45ac1f25cc5e..a3d8d3c9f37d 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -35,6 +35,7 @@ struct dxgprocess; struct dxgadapter; struct dxgdevice; +struct dxgcontext; =20 /* * Driver private data. @@ -298,6 +299,7 @@ void dxgadapter_remove_process(struct dxgprocess_adapte= r *process_info); /* * The object represent the device object. * The following objects take reference on the device + * - dxgcontext * - device handle (struct d3dkmthandle) */ struct dxgdevice { @@ -311,6 +313,8 @@ struct dxgdevice { struct kref device_kref; /* Protects destcruction of the device object */ struct rw_semaphore device_lock; + struct rw_semaphore context_list_lock; + struct list_head context_list_head; /* List of paging queues. Protected by process handle table lock. */ struct list_head pqueue_list_head; struct d3dkmthandle handle; @@ -325,7 +329,33 @@ void dxgdevice_mark_destroyed(struct dxgdevice *device= ); int dxgdevice_acquire_lock_shared(struct dxgdevice *dev); void dxgdevice_release_lock_shared(struct dxgdevice *dev); void dxgdevice_release(struct kref *refcount); +void dxgdevice_add_context(struct dxgdevice *dev, struct dxgcontext *ctx); +void dxgdevice_remove_context(struct dxgdevice *dev, struct dxgcontext *ct= x); bool dxgdevice_is_active(struct dxgdevice *dev); +void dxgdevice_acquire_context_list_lock(struct dxgdevice *dev); +void dxgdevice_release_context_list_lock(struct dxgdevice *dev); + +/* + * The object represent the execution context of a device. + */ +struct dxgcontext { + enum dxgobjectstate object_state; + struct dxgdevice *device; + struct dxgprocess *process; + /* entry in the device context list */ + struct list_head context_list_entry; + struct list_head hwqueue_list_head; + struct rw_semaphore hwqueue_list_lock; + struct kref context_kref; + struct d3dkmthandle handle; + struct d3dkmthandle device_handle; +}; + +struct dxgcontext *dxgcontext_create(struct dxgdevice *dev); +void dxgcontext_destroy(struct dxgprocess *pr, struct dxgcontext *ctx); +void dxgcontext_destroy_safe(struct dxgprocess *pr, struct dxgcontext *ctx= ); +void dxgcontext_release(struct kref *refcount); +bool dxgcontext_is_active(struct dxgcontext *ctx); =20 long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2); long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2= ); @@ -371,6 +401,14 @@ int dxgvmb_send_destroy_device(struct dxgadapter *adap= ter, struct d3dkmthandle h); int dxgvmb_send_flush_device(struct dxgdevice *device, enum dxgdevice_flushschedulerreason reason); +struct d3dkmthandle +dxgvmb_send_create_context(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmt_createcontextvirtual + *args); +int dxgvmb_send_destroy_context(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmthandle h); int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.c index 8373f681e822..ca307beb9a9a 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -257,6 +257,10 @@ struct dxgdevice *dxgprocess_device_by_object_handle(s= truct dxgprocess *process, case HMGRENTRY_TYPE_DXGDEVICE: device =3D obj; break; + case HMGRENTRY_TYPE_DXGCONTEXT: + device_handle =3D + ((struct dxgcontext *)obj)->device_handle; + break; default: DXG_ERR("invalid handle type: %d", t); break; diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 73804d11ec49..e66aac7c13cb 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -731,7 +731,7 @@ int dxgvmb_send_flush_device(struct dxgdevice *device, enum dxgdevice_flushschedulerreason reason) { int ret; - struct dxgkvmb_command_flushdevice *command; + struct dxgkvmb_command_flushdevice *command =3D NULL; struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; struct dxgprocess *process =3D device->process; =20 @@ -745,6 +745,105 @@ int dxgvmb_send_flush_device(struct dxgdevice *device, command->device =3D device->handle; command->reason =3D reason; =20 + ret =3D 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; +} + +struct d3dkmthandle +dxgvmb_send_create_context(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmt_createcontextvirtual *args) +{ + struct dxgkvmb_command_createcontextvirtual *command =3D NULL; + u32 cmd_size; + int ret; + struct d3dkmthandle context =3D {}; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + if (args->priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("PrivateDriverDataSize is invalid"); + ret =3D -EINVAL; + goto cleanup; + } + cmd_size =3D sizeof(struct dxgkvmb_command_createcontextvirtual) + + args->priv_drv_data_size - 1; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_CREATECONTEXTVIRTUAL, + process->host_handle); + command->device =3D args->device; + command->node_ordinal =3D args->node_ordinal; + command->engine_affinity =3D args->engine_affinity; + command->flags =3D args->flags; + command->client_hint =3D args->client_hint; + command->priv_drv_data_size =3D args->priv_drv_data_size; + if (args->priv_drv_data_size) { + ret =3D copy_from_user(command->priv_drv_data, + args->priv_drv_data, + args->priv_drv_data_size); + if (ret) { + DXG_ERR("Faled to copy private data"); + ret =3D -EINVAL; + goto cleanup; + } + } + /* Input command is returned back as output */ + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + command, cmd_size); + if (ret < 0) { + goto cleanup; + } else { + context =3D command->context; + if (args->priv_drv_data_size) { + ret =3D copy_to_user(args->priv_drv_data, + command->priv_drv_data, + args->priv_drv_data_size); + if (ret) { + dev_err(DXGDEV, + "Faled to copy private data to user"); + ret =3D -EINVAL; + dxgvmb_send_destroy_context(adapter, process, + context); + context.v =3D 0; + } + } + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return context; +} + +int dxgvmb_send_destroy_context(struct dxgadapter *adapter, + struct dxgprocess *process, + struct d3dkmthandle h) +{ + int ret; + struct dxgkvmb_command_destroycontext *command; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_DESTROYCONTEXT, + process->host_handle); + command->context =3D h; + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); cleanup: free_message(&msg, process); diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 4ccf45765954..ebcb7b0f62c1 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -269,4 +269,22 @@ struct dxgkvmb_command_flushdevice { enum dxgdevice_flushschedulerreason reason; }; =20 +struct dxgkvmb_command_createcontextvirtual { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle context; + struct d3dkmthandle device; + u32 node_ordinal; + u32 engine_affinity; + struct d3dddi_createcontextflags flags; + enum d3dkmt_clienthint client_hint; + u32 priv_drv_data_size; + u8 priv_drv_data[1]; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroycontext { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle context; +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 405e8b92913e..5d10ebd2ce6a 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -550,13 +550,177 @@ dxgkio_destroy_device(struct dxgprocess *process, vo= id *__user inargs) return ret; } =20 +static int +dxgkio_create_context_virtual(struct dxgprocess *process, void *__user ina= rgs) +{ + struct d3dkmt_createcontextvirtual args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxgcontext *context =3D NULL; + struct d3dkmthandle host_context_handle =3D {}; + bool device_lock_acquired =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) + goto cleanup; + + device_lock_acquired =3D true; + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + context =3D dxgcontext_create(device); + if (context =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + host_context_handle =3D dxgvmb_send_create_context(adapter, + process, &args); + if (host_context_handle.v) { + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(&process->handle_table, context, + HMGRENTRY_TYPE_DXGCONTEXT, + host_context_handle); + if (ret >=3D 0) + context->handle =3D host_context_handle; + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + if (ret < 0) + goto cleanup; + ret =3D copy_to_user(&((struct d3dkmt_createcontextvirtual *) + inargs)->context, &host_context_handle, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy context handle"); + ret =3D -EINVAL; + } + } else { + DXG_ERR("invalid host handle"); + ret =3D -EINVAL; + } + +cleanup: + + if (ret < 0) { + if (host_context_handle.v) { + dxgvmb_send_destroy_context(adapter, process, + host_context_handle); + } + if (context) + dxgcontext_destroy_safe(process, context); + } + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) { + if (device_lock_acquired) + dxgdevice_release_lock_shared(device); + kref_put(&device->device_kref, dxgdevice_release); + } + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_destroy_context(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_destroycontext args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgcontext *context =3D NULL; + struct dxgdevice *device =3D NULL; + struct d3dkmthandle device_handle =3D {}; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + context =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (context) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGCONTEXT, args.context); + context->handle.v =3D 0; + device_handle =3D context->device_handle; + context->object_state =3D DXGOBJECTSTATE_DESTROYED; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (context =3D=3D NULL) { + DXG_ERR("invalid context handle: %x", args.context.v); + ret =3D -EINVAL; + goto cleanup; + } + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, device_handle); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_destroy_context(adapter, process, args.context); + + dxgcontext_destroy_safe(process, context); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %s %d", errorstr(ret), __func__, ret); + return ret; +} + static struct ioctl_desc ioctls[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, /* 0x02 */ {dxgkio_create_device, LX_DXCREATEDEVICE}, /* 0x03 */ {}, -/* 0x04 */ {}, -/* 0x05 */ {}, +/* 0x04 */ {dxgkio_create_context_virtual, LX_DXCREATECONTEXTVIRTUAL}, +/* 0x05 */ {dxgkio_destroy_context, LX_DXDESTROYCONTEXT}, /* 0x06 */ {}, /* 0x07 */ {}, /* 0x08 */ {}, diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h index e0bd33b365b0..3a9637f0b5e2 100644 --- a/drivers/hv/dxgkrnl/misc.h +++ b/drivers/hv/dxgkrnl/misc.h @@ -29,6 +29,7 @@ extern const struct d3dkmthandle zerohandle; * fd_mutex * plistmutex (process list mutex) * table_lock (handle table lock) + * context_list_lock * core_lock (dxgadapter lock) * device_lock (dxgdevice lock) * process_adapter_mutex diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 7414f0f5ce8e..4ba0070b061f 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -154,6 +154,49 @@ struct d3dkmt_destroydevice { struct d3dkmthandle device; }; =20 +enum d3dkmt_clienthint { + _D3DKMT_CLIENTHNT_UNKNOWN =3D 0, + _D3DKMT_CLIENTHINT_OPENGL =3D 1, + _D3DKMT_CLIENTHINT_CDD =3D 2, + _D3DKMT_CLIENTHINT_DX7 =3D 7, + _D3DKMT_CLIENTHINT_DX8 =3D 8, + _D3DKMT_CLIENTHINT_DX9 =3D 9, + _D3DKMT_CLIENTHINT_DX10 =3D 10, +}; + +struct d3dddi_createcontextflags { + union { + struct { + __u32 null_rendering:1; + __u32 initial_data:1; + __u32 disable_gpu_timeout:1; + __u32 synchronization_only:1; + __u32 hw_queue_supported:1; + __u32 reserved:27; + }; + __u32 value; + }; +}; + +struct d3dkmt_destroycontext { + struct d3dkmthandle context; +}; + +struct d3dkmt_createcontextvirtual { + struct d3dkmthandle device; + __u32 node_ordinal; + __u32 engine_affinity; + struct d3dddi_createcontextflags flags; +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + __u32 priv_drv_data_size; + enum d3dkmt_clienthint client_hint; + struct d3dkmthandle context; +}; + struct d3dkmt_adaptertype { union { struct { @@ -232,6 +275,10 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x01, struct d3dkmt_openadapterfromluid) #define LX_DXCREATEDEVICE \ _IOWR(0x47, 0x02, struct d3dkmt_createdevice) +#define LX_DXCREATECONTEXTVIRTUAL \ + _IOWR(0x47, 0x04, struct d3dkmt_createcontextvirtual) +#define LX_DXDESTROYCONTEXT \ + _IOWR(0x47, 0x05, struct d3dkmt_destroycontext) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) #define LX_DXENUMADAPTERS2 \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f53.google.com (mail-wr1-f53.google.com [209.85.221.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8F0FB3F8807 for ; Thu, 19 Mar 2026 20:25:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951930; cv=none; b=hEBmLgeHO13c2MGTLDpEf7ewMxETN6PQzRzraaj2ojJDcvuLbc/FkvSfNF0zX1voaTqCPa0yMd1k5ufeh3ZGoUV90624kJRhapnePwpdtkgtVWpzYtvxauRPKFRTxxusGSlX+WNsWce3R1WbBMrGL07PL/VPcL1bO4lWnppVFls= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951930; c=relaxed/simple; bh=ykcYxFRO+ZtRrrWEmulJ6JomXCyYa4WjpN+psOjQaEI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZVT1bYDqgCNdGhnwxG0j8PUFG9UTLxlgSaHuwBKhWGExGEAPD5sa4ciZELcoRD3U1suGLXDzHKVhC2iQ5ZfW9cnvFvKIXtQ2PBig+wXbGyyGYHqwBpudF7ZczNc21CMKyqG5qStGt06oOIyUk1rDg7Pn4T+EvrBfYv491NTv570= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Ta5IjMBo; arc=none smtp.client-ip=209.85.221.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Ta5IjMBo" Received: by mail-wr1-f53.google.com with SMTP id ffacd0b85a97d-43b5bded412so661133f8f.0 for ; Thu, 19 Mar 2026 13:25:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951923; x=1774556723; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wXgMwf3Q/smgosHRFhAWqFDVKXuxmJD0K/nlx0MPjOM=; b=Ta5IjMBoSCjjVeEctbmWREU993DIAmek8HUv4h8nsaA1xBjKI2GTPSJwW8czoH9MGU TmSBEBfbqj6gWPV0DPGafqbbnuxC8GVz8s18Ru4F24US69fwhrGcThRmyZM4eIjQlnFq rZtUmwq8O1mFsEaq+y0XPAwZkzv/+JS9itltgl/vrMZy5Dk4nShDdLtxMExpeHLESu8/ f8JbFb5up8vFCJaUGxLW8WZL79m/Xna4i2YldZgWwihRsfzf0gtQaozEh5sUWtuc8J9T tQ4JMwSDFbSTEdaM4LuzB2nZ+ns0u5V0+6PfzbUquy0F/xVjk+lUNdkyNNE1La9w6ddc P8rw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951923; x=1774556723; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=wXgMwf3Q/smgosHRFhAWqFDVKXuxmJD0K/nlx0MPjOM=; b=CyyvoIf0+r3B4CqdmxwaI0RiGMhg69jyJj8UqbXlpgAi8jqrdw4O/FXxbWqN4J9MAX ldpZfMf6HlxGQ5dIhkMIj+uY4Y0jfc2U1mKAxXZfUiv42c9rh5EIPxVy91b+cLRDdv6Y BSiC1YRqLHRJbElXQW1ddff5oDIFbIHgoizVZtguThuULPiMljMoU0lVCBoqDC39wgDE xTFlmeDjxD3wo7cXY4/3y/Tga9Ozg6MrFHpIENwXjeLpREbkrTyDIxLeWtQciXgItZIg p6ogSU6jYbdK/ncGz/zNDlsa7lUiHKjAfvCE4IBAaWwc1/qd5wu9YiyqWcmcgWPX4O6u X0VA== X-Gm-Message-State: AOJu0YwEBpvC9xkXsItS9yeWVsKvKodOOoneBydbYjpafZGtrAP1DDmj aixa62QWyz8wnwlDJUjx4d6kk7V4PTTM9Y8gJ2e2hHoNG6i+P/v9uVeo X-Gm-Gg: ATEYQzyYwxJDwQVYgWw6jtiYpAeXdyISgjUro/zCLwRtbgIO4m4PfU6lmxiroCyo0lo BxX14LGTCeKofBAaUm1CwlV0iwdM9MlzuCZF3D2NiN0ixFABclX/sxQvBaiwyNvVHHLEr3cJCaJ CFbwfVI+eVj6L4Ys3/+6rnXhdFKopLv8ra9p3vApVNfp4Rho9JRc2xdUfFztYB99WnPPVkPFqcU u6reck3hbBkurDJhPF5FX//UZP5XoUEb6nWo/lNpMSRwsWPiynkHBAmF3hCB7eH8ZKC/kMe5gu1 mlxdEss7ok9AVDoJDqyo33G3KbBLW3E7/+h3PLV19uPuOKLkL1zIbUByPHcWyD8b9KhMuLsF8AR I/6ZEoax3w8yDPG1vfwy1vMTyCIBYdJMdo+y0339vU7MXIHdz+Pm7p754Yb/a8OjBfLIej4/GZF tBXA33ZaP94M6t5E6rDtyNBa+mjgY7jy8wiexPK2ZoeP1fHWp9 X-Received: by 2002:a5d:584a:0:b0:439:b736:bd0e with SMTP id ffacd0b85a97d-43b64271c2fmr1308762f8f.44.1773951922510; Thu, 19 Mar 2026 13:25:22 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.21 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:22 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 08/55] drivers: hv: dxgkrnl: Creation of compute device allocations and resources Date: Thu, 19 Mar 2026 20:24:22 +0000 Message-ID: <20260319202509.63802-9-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implemented ioctls to create and destroy virtual compute device allocations (dxgallocation) and resources (dxgresource): - the LX_DXCREATEALLOCATION ioctl, - the LX_DXDESTROYALLOCATION2 ioctl. Compute device allocations (dxgallocation objects) represent memory allocation, which could be accessible by the device. Allocations can be created around existing system memory (provided by an application) or memory, allocated by dxgkrnl on the host. Compute device resources (dxgresource objects) represent containers of compute device allocations. Allocations could be dynamically added, removed from a resource. Each allocation/resource has associated driver private data, which is provided during creation. Each created resource or allocation have a handle (d3dkmthandle), which is used to reference the corresponding object in other ioctls. A dxgallocation can be resident (meaning that it is accessible by the compute device) or evicted. When an allocation is evicted, its content is stored in the backing store in system memory. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 282 ++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 113 ++++++ drivers/hv/dxgkrnl/dxgmodule.c | 1 + drivers/hv/dxgkrnl/dxgvmbus.c | 649 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 123 ++++++ drivers/hv/dxgkrnl/ioctl.c | 631 ++++++++++++++++++++++++++++++- drivers/hv/dxgkrnl/misc.h | 3 + include/uapi/misc/d3dkmthk.h | 204 ++++++++++ 8 files changed, 2004 insertions(+), 2 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index cd103e092ac2..402caa81a5db 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -207,8 +207,11 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *= adapter, device->process =3D process; kref_get(&adapter->adapter_kref); INIT_LIST_HEAD(&device->context_list_head); + INIT_LIST_HEAD(&device->alloc_list_head); + INIT_LIST_HEAD(&device->resource_list_head); init_rwsem(&device->device_lock); init_rwsem(&device->context_list_lock); + init_rwsem(&device->alloc_list_lock); INIT_LIST_HEAD(&device->pqueue_list_head); device->object_state =3D DXGOBJECTSTATE_CREATED; device->execution_state =3D _D3DKMT_DEVICEEXECUTION_ACTIVE; @@ -224,6 +227,14 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *= adapter, =20 void dxgdevice_stop(struct dxgdevice *device) { + struct dxgallocation *alloc; + + DXG_TRACE("Destroying device: %p", device); + dxgdevice_acquire_alloc_list_lock(device); + list_for_each_entry(alloc, &device->alloc_list_head, alloc_list_entry) { + dxgallocation_stop(alloc); + } + dxgdevice_release_alloc_list_lock(device); } =20 void dxgdevice_mark_destroyed(struct dxgdevice *device) @@ -250,6 +261,33 @@ void dxgdevice_destroy(struct dxgdevice *device) =20 dxgdevice_stop(device); =20 + dxgdevice_acquire_alloc_list_lock(device); + + { + struct dxgallocation *alloc; + struct dxgallocation *tmp; + + DXG_TRACE("destroying allocations"); + list_for_each_entry_safe(alloc, tmp, &device->alloc_list_head, + alloc_list_entry) { + dxgallocation_destroy(alloc); + } + } + + { + struct dxgresource *resource; + struct dxgresource *tmp; + + DXG_TRACE("destroying resources"); + list_for_each_entry_safe(resource, tmp, + &device->resource_list_head, + resource_list_entry) { + dxgresource_destroy(resource); + } + } + + dxgdevice_release_alloc_list_lock(device); + { struct dxgcontext *context; struct dxgcontext *tmp; @@ -328,6 +366,26 @@ void dxgdevice_release_context_list_lock(struct dxgdev= ice *device) up_write(&device->context_list_lock); } =20 +void dxgdevice_acquire_alloc_list_lock(struct dxgdevice *device) +{ + down_write(&device->alloc_list_lock); +} + +void dxgdevice_release_alloc_list_lock(struct dxgdevice *device) +{ + up_write(&device->alloc_list_lock); +} + +void dxgdevice_acquire_alloc_list_lock_shared(struct dxgdevice *device) +{ + down_read(&device->alloc_list_lock); +} + +void dxgdevice_release_alloc_list_lock_shared(struct dxgdevice *device) +{ + up_read(&device->alloc_list_lock); +} + void dxgdevice_add_context(struct dxgdevice *device, struct dxgcontext *co= ntext) { down_write(&device->context_list_lock); @@ -344,6 +402,161 @@ void dxgdevice_remove_context(struct dxgdevice *devic= e, } } =20 +void dxgdevice_add_alloc(struct dxgdevice *device, struct dxgallocation *a= lloc) +{ + dxgdevice_acquire_alloc_list_lock(device); + list_add_tail(&alloc->alloc_list_entry, &device->alloc_list_head); + kref_get(&device->device_kref); + alloc->owner.device =3D device; + dxgdevice_release_alloc_list_lock(device); +} + +void dxgdevice_remove_alloc(struct dxgdevice *device, + struct dxgallocation *alloc) +{ + if (alloc->alloc_list_entry.next) { + list_del(&alloc->alloc_list_entry); + alloc->alloc_list_entry.next =3D NULL; + kref_put(&device->device_kref, dxgdevice_release); + } +} + +void dxgdevice_remove_alloc_safe(struct dxgdevice *device, + struct dxgallocation *alloc) +{ + dxgdevice_acquire_alloc_list_lock(device); + dxgdevice_remove_alloc(device, alloc); + dxgdevice_release_alloc_list_lock(device); +} + +void dxgdevice_add_resource(struct dxgdevice *device, struct dxgresource *= res) +{ + dxgdevice_acquire_alloc_list_lock(device); + list_add_tail(&res->resource_list_entry, &device->resource_list_head); + kref_get(&device->device_kref); + dxgdevice_release_alloc_list_lock(device); +} + +void dxgdevice_remove_resource(struct dxgdevice *device, + struct dxgresource *res) +{ + if (res->resource_list_entry.next) { + list_del(&res->resource_list_entry); + res->resource_list_entry.next =3D NULL; + kref_put(&device->device_kref, dxgdevice_release); + } +} + +struct dxgresource *dxgresource_create(struct dxgdevice *device) +{ + struct dxgresource *resource; + + resource =3D kzalloc(sizeof(struct dxgresource), GFP_KERNEL); + if (resource) { + kref_init(&resource->resource_kref); + resource->device =3D device; + resource->process =3D device->process; + resource->object_state =3D DXGOBJECTSTATE_ACTIVE; + mutex_init(&resource->resource_mutex); + INIT_LIST_HEAD(&resource->alloc_list_head); + dxgdevice_add_resource(device, resource); + } + return resource; +} + +void dxgresource_free_handle(struct dxgresource *resource) +{ + struct dxgallocation *alloc; + struct dxgprocess *process; + + if (resource->handle_valid) { + process =3D resource->device->process; + hmgrtable_free_handle_safe(&process->handle_table, + HMGRENTRY_TYPE_DXGRESOURCE, + resource->handle); + resource->handle_valid =3D 0; + } + list_for_each_entry(alloc, &resource->alloc_list_head, + alloc_list_entry) { + dxgallocation_free_handle(alloc); + } +} + +void dxgresource_destroy(struct dxgresource *resource) +{ + /* device->alloc_list_lock is held */ + struct dxgallocation *alloc; + struct dxgallocation *tmp; + struct d3dkmt_destroyallocation2 args =3D { }; + int destroyed =3D test_and_set_bit(0, &resource->flags); + struct dxgdevice *device =3D resource->device; + + if (!destroyed) { + dxgresource_free_handle(resource); + if (resource->handle.v) { + args.device =3D device->handle; + args.resource =3D resource->handle; + dxgvmb_send_destroy_allocation(device->process, + device, &args, NULL); + resource->handle.v =3D 0; + } + list_for_each_entry_safe(alloc, tmp, &resource->alloc_list_head, + alloc_list_entry) { + dxgallocation_destroy(alloc); + } + dxgdevice_remove_resource(device, resource); + } + kref_put(&resource->resource_kref, dxgresource_release); +} + +void dxgresource_release(struct kref *refcount) +{ + struct dxgresource *resource; + + resource =3D container_of(refcount, struct dxgresource, resource_kref); + kfree(resource); +} + +bool dxgresource_is_active(struct dxgresource *resource) +{ + return resource->object_state =3D=3D DXGOBJECTSTATE_ACTIVE; +} + +int dxgresource_add_alloc(struct dxgresource *resource, + struct dxgallocation *alloc) +{ + int ret =3D -ENODEV; + struct dxgdevice *device =3D resource->device; + + dxgdevice_acquire_alloc_list_lock(device); + if (dxgresource_is_active(resource)) { + list_add_tail(&alloc->alloc_list_entry, + &resource->alloc_list_head); + alloc->owner.resource =3D resource; + ret =3D 0; + } + alloc->resource_owner =3D 1; + dxgdevice_release_alloc_list_lock(device); + return ret; +} + +void dxgresource_remove_alloc(struct dxgresource *resource, + struct dxgallocation *alloc) +{ + if (alloc->alloc_list_entry.next) { + list_del(&alloc->alloc_list_entry); + alloc->alloc_list_entry.next =3D NULL; + } +} + +void dxgresource_remove_alloc_safe(struct dxgresource *resource, + struct dxgallocation *alloc) +{ + dxgdevice_acquire_alloc_list_lock(resource->device); + dxgresource_remove_alloc(resource, alloc); + dxgdevice_release_alloc_list_lock(resource->device); +} + void dxgdevice_release(struct kref *refcount) { struct dxgdevice *device; @@ -413,6 +626,75 @@ void dxgcontext_release(struct kref *refcount) kfree(context); } =20 +struct dxgallocation *dxgallocation_create(struct dxgprocess *process) +{ + struct dxgallocation *alloc; + + alloc =3D kzalloc(sizeof(struct dxgallocation), GFP_KERNEL); + if (alloc) + alloc->process =3D process; + return alloc; +} + +void dxgallocation_stop(struct dxgallocation *alloc) +{ + if (alloc->pages) { + release_pages(alloc->pages, alloc->num_pages); + vfree(alloc->pages); + alloc->pages =3D NULL; + } +} + +void dxgallocation_free_handle(struct dxgallocation *alloc) +{ + dxgprocess_ht_lock_exclusive_down(alloc->process); + if (alloc->handle_valid) { + hmgrtable_free_handle(&alloc->process->handle_table, + HMGRENTRY_TYPE_DXGALLOCATION, + alloc->alloc_handle); + alloc->handle_valid =3D 0; + } + dxgprocess_ht_lock_exclusive_up(alloc->process); +} + +void dxgallocation_destroy(struct dxgallocation *alloc) +{ + struct dxgprocess *process =3D alloc->process; + struct d3dkmt_destroyallocation2 args =3D { }; + + dxgallocation_stop(alloc); + if (alloc->resource_owner) + dxgresource_remove_alloc(alloc->owner.resource, alloc); + else if (alloc->owner.device) + dxgdevice_remove_alloc(alloc->owner.device, alloc); + dxgallocation_free_handle(alloc); + if (alloc->alloc_handle.v && !alloc->resource_owner) { + args.device =3D alloc->owner.device->handle; + args.alloc_count =3D 1; + dxgvmb_send_destroy_allocation(process, + 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 =3D 0; + } +else + if (alloc->gpadl) { + DXG_TRACE("Teardown gpadl %d", + alloc->gpadl); + vmbus_teardown_gpadl(dxgglobal_get_vmbus(), alloc->gpadl); + alloc->gpadl =3D 0; + } +#endif + if (alloc->priv_drv_data) + vfree(alloc->priv_drv_data); + kfree(alloc); +} + struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *pr= ocess, struct dxgadapter *adapter) { diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index a3d8d3c9f37d..fa053fb6ac9c 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -36,6 +36,8 @@ struct dxgprocess; struct dxgadapter; struct dxgdevice; struct dxgcontext; +struct dxgallocation; +struct dxgresource; =20 /* * Driver private data. @@ -269,6 +271,8 @@ struct dxgadapter { struct list_head adapter_list_entry; /* The list of dxgprocess_adapter entries */ struct list_head adapter_process_list_head; + /* This lock protects shared resource and syncobject lists */ + struct rw_semaphore shared_resource_list_lock; struct pci_dev *pci_dev; struct hv_device *hv_dev; struct dxgvmbuschannel channel; @@ -315,6 +319,10 @@ struct dxgdevice { struct rw_semaphore device_lock; struct rw_semaphore context_list_lock; struct list_head context_list_head; + /* List of device allocations */ + struct rw_semaphore alloc_list_lock; + struct list_head alloc_list_head; + struct list_head resource_list_head; /* List of paging queues. Protected by process handle table lock. */ struct list_head pqueue_list_head; struct d3dkmthandle handle; @@ -331,9 +339,19 @@ void dxgdevice_release_lock_shared(struct dxgdevice *d= ev); void dxgdevice_release(struct kref *refcount); void dxgdevice_add_context(struct dxgdevice *dev, struct dxgcontext *ctx); void dxgdevice_remove_context(struct dxgdevice *dev, struct dxgcontext *ct= x); +void dxgdevice_add_alloc(struct dxgdevice *dev, struct dxgallocation *a); +void dxgdevice_remove_alloc(struct dxgdevice *dev, struct dxgallocation *a= ); +void dxgdevice_remove_alloc_safe(struct dxgdevice *dev, + struct dxgallocation *a); +void dxgdevice_add_resource(struct dxgdevice *dev, struct dxgresource *res= ); +void dxgdevice_remove_resource(struct dxgdevice *dev, struct dxgresource *= res); bool dxgdevice_is_active(struct dxgdevice *dev); void dxgdevice_acquire_context_list_lock(struct dxgdevice *dev); void dxgdevice_release_context_list_lock(struct dxgdevice *dev); +void dxgdevice_acquire_alloc_list_lock(struct dxgdevice *dev); +void dxgdevice_release_alloc_list_lock(struct dxgdevice *dev); +void dxgdevice_acquire_alloc_list_lock_shared(struct dxgdevice *dev); +void dxgdevice_release_alloc_list_lock_shared(struct dxgdevice *dev); =20 /* * The object represent the execution context of a device. @@ -357,6 +375,83 @@ void dxgcontext_destroy_safe(struct dxgprocess *pr, st= ruct dxgcontext *ctx); void dxgcontext_release(struct kref *refcount); bool dxgcontext_is_active(struct dxgcontext *ctx); =20 +struct dxgresource { + struct kref resource_kref; + enum dxgobjectstate object_state; + struct d3dkmthandle handle; + struct list_head alloc_list_head; + struct list_head resource_list_entry; + struct list_head shared_resource_list_entry; + struct dxgdevice *device; + struct dxgprocess *process; + /* Protects adding allocations to resource and resource destruction */ + struct mutex resource_mutex; + u64 private_runtime_handle; + union { + struct { + u32 destroyed:1; /* Must be the first */ + u32 handle_valid:1; + u32 reserved:30; + }; + long flags; + }; +}; + +struct dxgresource *dxgresource_create(struct dxgdevice *dev); +void dxgresource_destroy(struct dxgresource *res); +void dxgresource_free_handle(struct dxgresource *res); +void dxgresource_release(struct kref *refcount); +int dxgresource_add_alloc(struct dxgresource *res, + struct dxgallocation *a); +void dxgresource_remove_alloc(struct dxgresource *res, struct dxgallocatio= n *a); +void dxgresource_remove_alloc_safe(struct dxgresource *res, + struct dxgallocation *a); +bool dxgresource_is_active(struct dxgresource *res); + +struct privdata { + u32 data_size; + u8 data[1]; +}; + +struct dxgallocation { + /* Entry in the device list or resource list (when resource exists) */ + struct list_head alloc_list_entry; + /* Allocation owner */ + union { + struct dxgdevice *device; + struct dxgresource *resource; + } owner; + struct dxgprocess *process; + /* Pointer to private driver data desc. Used for shared resources */ + struct privdata *priv_drv_data; + struct d3dkmthandle alloc_handle; + /* Set to 1 when allocation belongs to resource. */ + u32 resource_owner:1; + /* Set to 1 when the allocatio is mapped as cached */ + 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; + /* + * CPU address from the existing sysmem allocation, or + * mapped to the CPU visible backing store in the IO space + */ + void *cpu_address; + /* Describes pages for the existing sysmem allocation */ + struct page **pages; +}; + +struct dxgallocation *dxgallocation_create(struct dxgprocess *process); +void dxgallocation_stop(struct dxgallocation *a); +void dxgallocation_destroy(struct dxgallocation *a); +void dxgallocation_free_handle(struct dxgallocation *a); + long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2); long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2= ); =20 @@ -409,9 +504,27 @@ dxgvmb_send_create_context(struct dxgadapter *adapter, int dxgvmb_send_destroy_context(struct dxgadapter *adapter, struct dxgprocess *process, struct d3dkmthandle h); +int dxgvmb_send_create_allocation(struct dxgprocess *pr, struct dxgdevice = *dev, + struct d3dkmt_createallocation *args, + struct d3dkmt_createallocation *__user inargs, + struct dxgresource *res, + struct dxgallocation **allocs, + struct d3dddi_allocationinfo2 *alloc_info, + struct d3dkmt_createstandardallocation *stda); +int dxgvmb_send_destroy_allocation(struct dxgprocess *pr, struct dxgdevice= *dev, + struct d3dkmt_destroyallocation2 *args, + struct d3dkmthandle *alloc_handles); int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); +int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device, + enum d3dkmdt_standardallocationtype t, + struct d3dkmdt_gdisurfacedata *data, + u32 physical_adapter_index, + u32 *alloc_priv_driver_size, + void *prive_alloc_data, + u32 *res_priv_data_size, + void *priv_res_data); int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel, void *command, u32 cmd_size); diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index fbe1c58ecb46..053ce6f3e083 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -162,6 +162,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_= t *guid, init_rwsem(&adapter->core_lock); =20 INIT_LIST_HEAD(&adapter->adapter_process_list_head); + init_rwsem(&adapter->shared_resource_list_lock); adapter->pci_dev =3D dev; guid_to_luid(guid, &adapter->luid); =20 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index e66aac7c13cb..14b51a3c6afc 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -111,6 +111,41 @@ static int init_message(struct dxgvmbusmsg *msg, struc= t dxgadapter *adapter, return 0; } =20 +static int init_message_res(struct dxgvmbusmsgres *msg, + struct dxgadapter *adapter, + struct dxgprocess *process, + u32 size, + u32 result_size) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + bool use_ext_header =3D dxgglobal->vmbus_ver >=3D + DXGK_VMBUS_INTERFACE_VERSION; + + if (use_ext_header) + size +=3D sizeof(struct dxgvmb_ext_header); + msg->size =3D size; + msg->res_size +=3D (result_size + 7) & ~7; + size +=3D msg->res_size; + msg->hdr =3D vzalloc(size); + if (msg->hdr =3D=3D NULL) { + DXG_ERR("Failed to allocate VM bus message: %d", size); + return -ENOMEM; + } + if (use_ext_header) { + msg->msg =3D (char *)&msg->hdr[1]; + msg->hdr->command_offset =3D sizeof(msg->hdr[0]); + msg->hdr->vgpu_luid =3D adapter->host_vgpu_luid; + } else { + msg->msg =3D (char *)msg->hdr; + } + msg->res =3D (char *)msg->hdr + msg->size; + if (dxgglobal->async_msg_enabled) + msg->channel =3D &dxgglobal->channel; + else + msg->channel =3D &adapter->channel; + return 0; +} + static void free_message(struct dxgvmbusmsg *msg, struct dxgprocess *proce= ss) { if (msg->hdr && (char *)msg->hdr !=3D msg->msg_on_stack) @@ -852,6 +887,620 @@ int dxgvmb_send_destroy_context(struct dxgadapter *ad= apter, return ret; } =20 +static int +copy_private_data(struct d3dkmt_createallocation *args, + struct dxgkvmb_command_createallocation *command, + struct d3dddi_allocationinfo2 *input_alloc_info, + struct d3dkmt_createstandardallocation *standard_alloc) +{ + struct dxgkvmb_command_createallocation_allocinfo *alloc_info; + struct d3dddi_allocationinfo2 *input_alloc; + int ret =3D 0; + int i; + u8 *private_data_dest =3D (u8 *) &command[1] + + (args->alloc_count * + sizeof(struct dxgkvmb_command_createallocation_allocinfo)); + + if (args->private_runtime_data_size) { + ret =3D copy_from_user(private_data_dest, + args->private_runtime_data, + args->private_runtime_data_size); + if (ret) { + DXG_ERR("failed to copy runtime data"); + ret =3D -EINVAL; + goto cleanup; + } + private_data_dest +=3D args->private_runtime_data_size; + } + + if (args->flags.standard_allocation) { + DXG_TRACE("private data offset %d", + (u32) (private_data_dest - (u8 *) command)); + + args->priv_drv_data_size =3D sizeof(*args->standard_allocation); + memcpy(private_data_dest, standard_alloc, + sizeof(*standard_alloc)); + private_data_dest +=3D args->priv_drv_data_size; + } else if (args->priv_drv_data_size) { + ret =3D copy_from_user(private_data_dest, + args->priv_drv_data, + args->priv_drv_data_size); + if (ret) { + DXG_ERR("failed to copy private data"); + ret =3D -EINVAL; + goto cleanup; + } + private_data_dest +=3D args->priv_drv_data_size; + } + + alloc_info =3D (void *)&command[1]; + input_alloc =3D input_alloc_info; + if (input_alloc_info[0].sysmem) + command->flags.existing_sysmem =3D 1; + for (i =3D 0; i < args->alloc_count; i++) { + alloc_info->flags =3D input_alloc->flags.value; + alloc_info->vidpn_source_id =3D input_alloc->vidpn_source_id; + alloc_info->priv_drv_data_size =3D + input_alloc->priv_drv_data_size; + if (input_alloc->priv_drv_data_size) { + ret =3D copy_from_user(private_data_dest, + input_alloc->priv_drv_data, + input_alloc->priv_drv_data_size); + if (ret) { + DXG_ERR("failed to copy alloc data"); + ret =3D -EINVAL; + goto cleanup; + } + private_data_dest +=3D input_alloc->priv_drv_data_size; + } + alloc_info++; + input_alloc++; + } + +cleanup: + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +static +int create_existing_sysmem(struct dxgdevice *device, + struct dxgkvmb_command_allocinfo_return *host_alloc, + struct dxgallocation *dxgalloc, + bool read_only, + const void *sysmem) +{ + int ret1 =3D 0; + void *kmem =3D NULL; + int ret =3D 0; + struct dxgkvmb_command_setexistingsysmemstore *set_store_command; + u64 alloc_size =3D host_alloc->allocation_size; + u32 npages =3D alloc_size >> PAGE_SHIFT; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, device->adapter, device->process, + sizeof(*set_store_command)); + if (ret) + goto cleanup; + set_store_command =3D (void *)msg.msg; + + /* + * Create a guest physical address list and set it as the allocation + * backing store in the host. This is done after creating the host + * allocation, because only now the allocation size is known. + */ + + DXG_TRACE("Alloc size: %lld", alloc_size); + + dxgalloc->cpu_address =3D (void *)sysmem; + dxgalloc->pages =3D vzalloc(npages * sizeof(void *)); + if (dxgalloc->pages =3D=3D NULL) { + DXG_ERR("failed to allocate pages"); + ret =3D -ENOMEM; + goto cleanup; + } + ret1 =3D get_user_pages_fast((unsigned long)sysmem, npages, !read_only, + dxgalloc->pages); + if (ret1 !=3D npages) { + DXG_ERR("get_user_pages_fast failed: %d", ret1); + if (ret1 > 0 && ret1 < npages) + release_pages(dxgalloc->pages, ret1); + vfree(dxgalloc->pages); + dxgalloc->pages =3D NULL; + ret =3D -ENOMEM; + goto cleanup; + } + kmem =3D vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL); + if (kmem =3D=3D NULL) { + DXG_ERR("vmap failed"); + ret =3D -ENOMEM; + goto cleanup; + } + ret1 =3D vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem, + alloc_size, &dxgalloc->gpadl); + if (ret1) { + DXG_ERR("establish_gpadl failed: %d", ret1); + ret =3D -ENOMEM; + goto cleanup; + } + DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle); + + command_vgpu_to_host_init2(&set_store_command->hdr, + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE, + device->process->host_handle); + set_store_command->device =3D device->handle; + set_store_command->device =3D device->handle; + set_store_command->allocation =3D host_alloc->allocation; +#ifdef _MAIN_KERNEL_ + set_store_command->gpadl =3D dxgalloc->gpadl.gpadl_handle; +#else + set_store_command->gpadl =3D dxgalloc->gpadl; +#endif + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); + if (ret < 0) + DXG_ERR("failed to set existing store: %x", ret); + +cleanup: + if (kmem) + vunmap(kmem); + free_message(&msg, device->process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +static int +process_allocation_handles(struct dxgprocess *process, + struct dxgdevice *device, + struct d3dkmt_createallocation *args, + struct dxgkvmb_command_createallocation_return *res, + struct dxgallocation **dxgalloc, + struct dxgresource *resource) +{ + int ret =3D 0; + int i; + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + if (args->flags.create_resource) { + ret =3D hmgrtable_assign_handle(&process->handle_table, resource, + HMGRENTRY_TYPE_DXGRESOURCE, + res->resource); + if (ret < 0) { + DXG_ERR("failed to assign resource handle %x", + res->resource.v); + } else { + resource->handle =3D res->resource; + resource->handle_valid =3D 1; + } + } + for (i =3D 0; i < args->alloc_count; i++) { + struct dxgkvmb_command_allocinfo_return *host_alloc; + + host_alloc =3D &res->allocation_info[i]; + ret =3D hmgrtable_assign_handle(&process->handle_table, + dxgalloc[i], + HMGRENTRY_TYPE_DXGALLOCATION, + host_alloc->allocation); + if (ret < 0) { + DXG_ERR("failed assign alloc handle %x %d %d", + host_alloc->allocation.v, + args->alloc_count, i); + break; + } + dxgalloc[i]->alloc_handle =3D host_alloc->allocation; + dxgalloc[i]->handle_valid =3D 1; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +static int +create_local_allocations(struct dxgprocess *process, + struct dxgdevice *device, + struct d3dkmt_createallocation *args, + struct d3dkmt_createallocation *__user input_args, + struct d3dddi_allocationinfo2 *alloc_info, + struct dxgkvmb_command_createallocation_return *result, + struct dxgresource *resource, + struct dxgallocation **dxgalloc, + u32 destroy_buffer_size) +{ + int i; + int alloc_count =3D args->alloc_count; + u8 *alloc_private_data =3D NULL; + int ret =3D 0; + int ret1; + struct dxgkvmb_command_destroyallocation *destroy_buf; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, device->adapter, process, + destroy_buffer_size); + if (ret) + goto cleanup; + destroy_buf =3D (void *)msg.msg; + + /* Prepare the command to destroy allocation in case of failure */ + command_vgpu_to_host_init2(&destroy_buf->hdr, + DXGK_VMBCOMMAND_DESTROYALLOCATION, + process->host_handle); + destroy_buf->device =3D args->device; + destroy_buf->resource =3D args->resource; + destroy_buf->alloc_count =3D alloc_count; + destroy_buf->flags.assume_not_in_use =3D 1; + for (i =3D 0; i < alloc_count; i++) { + DXG_TRACE("host allocation: %d %x", + i, result->allocation_info[i].allocation.v); + destroy_buf->allocations[i] =3D + result->allocation_info[i].allocation; + } + + if (args->flags.create_resource) { + DXG_TRACE("new resource: %x", result->resource.v); + ret =3D copy_to_user(&input_args->resource, &result->resource, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy resource handle"); + ret =3D -EINVAL; + goto cleanup; + } + } + + alloc_private_data =3D (u8 *) result + + sizeof(struct dxgkvmb_command_createallocation_return) + + sizeof(struct dxgkvmb_command_allocinfo_return) * (alloc_count - 1); + + for (i =3D 0; i < alloc_count; i++) { + struct dxgkvmb_command_allocinfo_return *host_alloc; + struct d3dddi_allocationinfo2 *user_alloc; + + host_alloc =3D &result->allocation_info[i]; + user_alloc =3D &alloc_info[i]; + dxgalloc[i]->num_pages =3D + host_alloc->allocation_size >> PAGE_SHIFT; + if (user_alloc->sysmem) { + ret =3D create_existing_sysmem(device, host_alloc, + dxgalloc[i], + args->flags.read_only !=3D 0, + user_alloc->sysmem); + if (ret < 0) + goto cleanup; + } + dxgalloc[i]->cached =3D host_alloc->allocation_flags.cached; + if (host_alloc->priv_drv_data_size) { + ret =3D copy_to_user(user_alloc->priv_drv_data, + alloc_private_data, + host_alloc->priv_drv_data_size); + if (ret) { + DXG_ERR("failed to copy private data"); + ret =3D -EINVAL; + goto cleanup; + } + alloc_private_data +=3D host_alloc->priv_drv_data_size; + } + ret =3D copy_to_user(&args->allocation_info[i].allocation, + &host_alloc->allocation, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy alloc handle"); + ret =3D -EINVAL; + goto cleanup; + } + } + + ret =3D process_allocation_handles(process, device, args, result, + dxgalloc, resource); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(&input_args->global_share, &args->global_share, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy global share"); + ret =3D -EINVAL; + } + +cleanup: + + if (ret < 0) { + /* Free local handles before freeing the handles in the host */ + dxgdevice_acquire_alloc_list_lock(device); + if (dxgalloc) + for (i =3D 0; i < alloc_count; i++) + if (dxgalloc[i]) + dxgallocation_free_handle(dxgalloc[i]); + if (resource && args->flags.create_resource) + dxgresource_free_handle(resource); + dxgdevice_release_alloc_list_lock(device); + + /* Destroy allocations in the host to unmap gpadls */ + ret1 =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, + msg.size); + if (ret1 < 0) + DXG_ERR("failed to destroy allocations: %x", + ret1); + + dxgdevice_acquire_alloc_list_lock(device); + if (dxgalloc) { + for (i =3D 0; i < alloc_count; i++) { + if (dxgalloc[i]) { + dxgalloc[i]->alloc_handle.v =3D 0; + dxgallocation_destroy(dxgalloc[i]); + dxgalloc[i] =3D NULL; + } + } + } + if (resource && args->flags.create_resource) { + /* + * Prevent the resource memory from freeing. + * It will be freed in the top level function. + */ + kref_get(&resource->resource_kref); + dxgresource_destroy(resource); + } + dxgdevice_release_alloc_list_lock(device); + } + + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_create_allocation(struct dxgprocess *process, + struct dxgdevice *device, + struct d3dkmt_createallocation *args, + struct d3dkmt_createallocation *__user + input_args, + struct dxgresource *resource, + struct dxgallocation **dxgalloc, + struct d3dddi_allocationinfo2 *alloc_info, + struct d3dkmt_createstandardallocation + *standard_alloc) +{ + struct dxgkvmb_command_createallocation *command =3D NULL; + struct dxgkvmb_command_createallocation_return *result =3D NULL; + int ret =3D -EINVAL; + int i; + u32 result_size =3D 0; + u32 cmd_size =3D 0; + u32 destroy_buffer_size =3D 0; + u32 priv_drv_data_size; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + if (args->private_runtime_data_size >=3D DXG_MAX_VM_BUS_PACKET_SIZE || + args->priv_drv_data_size >=3D DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EOVERFLOW; + goto cleanup; + } + + /* + * Preallocate the buffer, which will be used for destruction in case + * of a failure + */ + destroy_buffer_size =3D sizeof(struct dxgkvmb_command_destroyallocation) + + args->alloc_count * sizeof(struct d3dkmthandle); + + /* Compute the total private driver size */ + + priv_drv_data_size =3D 0; + + for (i =3D 0; i < args->alloc_count; i++) { + if (alloc_info[i].priv_drv_data_size >=3D + DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EOVERFLOW; + goto cleanup; + } else { + priv_drv_data_size +=3D alloc_info[i].priv_drv_data_size; + } + if (priv_drv_data_size >=3D DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EOVERFLOW; + goto cleanup; + } + } + + /* + * Private driver data for the result includes only per allocation + * private data + */ + result_size =3D sizeof(struct dxgkvmb_command_createallocation_return) + + (args->alloc_count - 1) * + sizeof(struct dxgkvmb_command_allocinfo_return) + + priv_drv_data_size; + result =3D vzalloc(result_size); + if (result =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + /* Private drv data for the command includes the global private data */ + priv_drv_data_size +=3D args->priv_drv_data_size; + + cmd_size =3D sizeof(struct dxgkvmb_command_createallocation) + + args->alloc_count * + sizeof(struct dxgkvmb_command_createallocation_allocinfo) + + args->private_runtime_data_size + priv_drv_data_size; + if (cmd_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EOVERFLOW; + goto cleanup; + } + + DXG_TRACE("command size, driver_data_size %d %d %ld %ld", + cmd_size, priv_drv_data_size, + sizeof(struct dxgkvmb_command_createallocation), + sizeof(struct dxgkvmb_command_createallocation_allocinfo)); + + ret =3D init_message(&msg, device->adapter, process, + cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_CREATEALLOCATION, + process->host_handle); + command->device =3D args->device; + command->flags =3D args->flags; + command->resource =3D args->resource; + command->private_runtime_resource_handle =3D + args->private_runtime_resource_handle; + command->alloc_count =3D args->alloc_count; + command->private_runtime_data_size =3D args->private_runtime_data_size; + command->priv_drv_data_size =3D args->priv_drv_data_size; + + ret =3D copy_private_data(args, command, alloc_info, standard_alloc); + if (ret < 0) + goto cleanup; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + result, result_size); + if (ret < 0) { + DXG_ERR("send_create_allocation failed %x", ret); + goto cleanup; + } + + ret =3D create_local_allocations(process, device, args, input_args, + alloc_info, result, resource, dxgalloc, + destroy_buffer_size); +cleanup: + + if (result) + vfree(result); + free_message(&msg, process); + + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_destroy_allocation(struct dxgprocess *process, + struct dxgdevice *device, + struct d3dkmt_destroyallocation2 *args, + struct d3dkmthandle *alloc_handles) +{ + struct dxgkvmb_command_destroyallocation *destroy_buffer; + u32 destroy_buffer_size; + int ret; + int allocations_size =3D args->alloc_count * sizeof(struct d3dkmthandle); + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + destroy_buffer_size =3D sizeof(struct dxgkvmb_command_destroyallocation) + + allocations_size; + + ret =3D init_message(&msg, device->adapter, process, + destroy_buffer_size); + if (ret) + goto cleanup; + destroy_buffer =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&destroy_buffer->hdr, + DXGK_VMBCOMMAND_DESTROYALLOCATION, + process->host_handle); + destroy_buffer->device =3D args->device; + destroy_buffer->resource =3D args->resource; + destroy_buffer->alloc_count =3D args->alloc_count; + destroy_buffer->flags =3D args->flags; + if (allocations_size) + memcpy(destroy_buffer->allocations, alloc_handles, + allocations_size); + + ret =3D 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_get_stdalloc_data(struct dxgdevice *device, + enum d3dkmdt_standardallocationtype alloctype, + struct d3dkmdt_gdisurfacedata *alloc_data, + u32 physical_adapter_index, + u32 *alloc_priv_driver_size, + void *priv_alloc_data, + u32 *res_priv_data_size, + void *priv_res_data) +{ + struct dxgkvmb_command_getstandardallocprivdata *command; + struct dxgkvmb_command_getstandardallocprivdata_return *result =3D NULL; + u32 result_size =3D sizeof(*result); + int ret; + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; + + if (priv_alloc_data) + result_size +=3D *alloc_priv_driver_size; + if (priv_res_data) + result_size +=3D *res_priv_data_size; + ret =3D init_message_res(&msg, device->adapter, device->process, + sizeof(*command), result_size); + if (ret) + goto cleanup; + command =3D msg.msg; + result =3D msg.res; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_DDIGETSTANDARDALLOCATIONDRIVERDATA, + device->process->host_handle); + + command->alloc_type =3D alloctype; + command->priv_driver_data_size =3D *alloc_priv_driver_size; + command->physical_adapter_index =3D physical_adapter_index; + command->priv_driver_resource_size =3D *res_priv_data_size; + switch (alloctype) { + case _D3DKMDT_STANDARDALLOCATION_GDISURFACE: + command->gdi_surface =3D *alloc_data; + break; + case _D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE: + case _D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE: + case _D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE: + default: + DXG_ERR("Invalid standard alloc type"); + goto cleanup; + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + result, msg.res_size); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result->status); + if (ret < 0) + goto cleanup; + + if (*alloc_priv_driver_size && + result->priv_driver_data_size !=3D *alloc_priv_driver_size) { + DXG_ERR("Priv data size mismatch"); + goto cleanup; + } + if (*res_priv_data_size && + result->priv_driver_resource_size !=3D *res_priv_data_size) { + DXG_ERR("Resource priv data size mismatch"); + goto cleanup; + } + *alloc_priv_driver_size =3D result->priv_driver_data_size; + *res_priv_data_size =3D result->priv_driver_resource_size; + if (priv_alloc_data) { + memcpy(priv_alloc_data, &result[1], + result->priv_driver_data_size); + } + if (priv_res_data) { + memcpy(priv_res_data, + (char *)(&result[1]) + result->priv_driver_data_size, + result->priv_driver_resource_size); + } + +cleanup: + + free_message((struct dxgvmbusmsg *)&msg, device->process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index ebcb7b0f62c1..4b7466d1b9f2 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -173,6 +173,14 @@ struct dxgkvmb_command_setiospaceregion { u32 shared_page_gpadl; }; =20 +/* Returns ntstatus */ +struct dxgkvmb_command_setexistingsysmemstore { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + struct d3dkmthandle allocation; + u32 gpadl; +}; + struct dxgkvmb_command_createprocess { struct dxgkvmb_command_vm_to_host hdr; void *process; @@ -269,6 +277,121 @@ struct dxgkvmb_command_flushdevice { enum dxgdevice_flushschedulerreason reason; }; =20 +struct dxgkvmb_command_createallocation_allocinfo { + u32 flags; + u32 priv_drv_data_size; + u32 vidpn_source_id; +}; + +struct dxgkvmb_command_createallocation { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + struct d3dkmthandle resource; + u32 private_runtime_data_size; + u32 priv_drv_data_size; + u32 alloc_count; + struct d3dkmt_createallocationflags flags; + u64 private_runtime_resource_handle; + bool make_resident; +/* dxgkvmb_command_createallocation_allocinfo alloc_info[alloc_count]; */ +/* u8 private_rutime_data[private_runtime_data_size] */ +/* u8 priv_drv_data[] for each alloc_info */ +}; + +struct dxgkvmb_command_getstandardallocprivdata { + struct dxgkvmb_command_vgpu_to_host hdr; + enum d3dkmdt_standardallocationtype alloc_type; + u32 priv_driver_data_size; + u32 priv_driver_resource_size; + u32 physical_adapter_index; + union { + struct d3dkmdt_sharedprimarysurfacedata primary; + struct d3dkmdt_shadowsurfacedata shadow; + struct d3dkmdt_stagingsurfacedata staging; + struct d3dkmdt_gdisurfacedata gdi_surface; + }; +}; + +struct dxgkvmb_command_getstandardallocprivdata_return { + struct ntstatus status; + u32 priv_driver_data_size; + u32 priv_driver_resource_size; + union { + struct d3dkmdt_sharedprimarysurfacedata primary; + struct d3dkmdt_shadowsurfacedata shadow; + struct d3dkmdt_stagingsurfacedata staging; + struct d3dkmdt_gdisurfacedata gdi_surface; + }; +/* char alloc_priv_data[priv_driver_data_size]; */ +/* char resource_priv_data[priv_driver_resource_size]; */ +}; + +struct dxgkarg_describeallocation { + u64 allocation; + u32 width; + u32 height; + u32 format; + u32 multisample_method; + struct d3dddi_rational refresh_rate; + u32 private_driver_attribute; + u32 flags; + u32 rotation; +}; + +struct dxgkvmb_allocflags { + union { + u32 flags; + struct { + u32 primary:1; + u32 cdd_primary:1; + u32 dod_primary:1; + u32 overlay:1; + u32 reserved6:1; + u32 capture:1; + u32 reserved0:4; + u32 reserved1:1; + u32 existing_sysmem:1; + u32 stereo:1; + u32 direct_flip:1; + u32 hardware_protected:1; + u32 reserved2:1; + u32 reserved3:1; + u32 reserved4:1; + u32 protected:1; + u32 cached:1; + u32 independent_primary:1; + u32 reserved:11; + }; + }; +}; + +struct dxgkvmb_command_allocinfo_return { + struct d3dkmthandle allocation; + u32 priv_drv_data_size; + struct dxgkvmb_allocflags allocation_flags; + u64 allocation_size; + struct dxgkarg_describeallocation driver_info; +}; + +struct dxgkvmb_command_createallocation_return { + struct d3dkmt_createallocationflags flags; + struct d3dkmthandle resource; + struct d3dkmthandle global_share; + u32 vgpu_flags; + struct dxgkvmb_command_allocinfo_return allocation_info[1]; + /* Private driver data for allocations */ +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroyallocation { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + struct d3dkmthandle resource; + u32 alloc_count; + struct d3dddicb_destroyallocation2flags flags; + struct d3dkmthandle allocations[1]; +}; + struct dxgkvmb_command_createcontextvirtual { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmthandle context; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 5d10ebd2ce6a..0eaa577d7ed4 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -714,6 +714,633 @@ dxgkio_destroy_context(struct dxgprocess *process, vo= id *__user inargs) return ret; } =20 +static int +get_standard_alloc_priv_data(struct dxgdevice *device, + struct d3dkmt_createstandardallocation *alloc_info, + u32 *standard_alloc_priv_data_size, + void **standard_alloc_priv_data, + u32 *standard_res_priv_data_size, + void **standard_res_priv_data) +{ + int ret; + struct d3dkmdt_gdisurfacedata gdi_data =3D { }; + u32 priv_data_size =3D 0; + u32 res_priv_data_size =3D 0; + void *priv_data =3D NULL; + void *res_priv_data =3D NULL; + + gdi_data.type =3D _D3DKMDT_GDISURFACE_TEXTURE_CROSSADAPTER; + gdi_data.width =3D alloc_info->existing_heap_data.size; + gdi_data.height =3D 1; + gdi_data.format =3D _D3DDDIFMT_UNKNOWN; + + *standard_alloc_priv_data_size =3D 0; + ret =3D dxgvmb_send_get_stdalloc_data(device, + _D3DKMDT_STANDARDALLOCATION_GDISURFACE, + &gdi_data, 0, + &priv_data_size, NULL, + &res_priv_data_size, + NULL); + if (ret < 0) + goto cleanup; + DXG_TRACE("Priv data size: %d", priv_data_size); + if (priv_data_size =3D=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + priv_data =3D vzalloc(priv_data_size); + if (priv_data =3D=3D NULL) { + ret =3D -ENOMEM; + DXG_ERR("failed to allocate memory for priv data: %d", + priv_data_size); + goto cleanup; + } + if (res_priv_data_size) { + res_priv_data =3D vzalloc(res_priv_data_size); + if (res_priv_data =3D=3D NULL) { + ret =3D -ENOMEM; + dev_err(DXGDEV, + "failed to alloc memory for res priv data: %d", + res_priv_data_size); + goto cleanup; + } + } + ret =3D dxgvmb_send_get_stdalloc_data(device, + _D3DKMDT_STANDARDALLOCATION_GDISURFACE, + &gdi_data, 0, + &priv_data_size, + priv_data, + &res_priv_data_size, + res_priv_data); + if (ret < 0) + goto cleanup; + *standard_alloc_priv_data_size =3D priv_data_size; + *standard_alloc_priv_data =3D priv_data; + *standard_res_priv_data_size =3D res_priv_data_size; + *standard_res_priv_data =3D res_priv_data; + priv_data =3D NULL; + res_priv_data =3D NULL; + +cleanup: + if (priv_data) + vfree(priv_data); + if (res_priv_data) + vfree(res_priv_data); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +static int +dxgkio_create_allocation(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_createallocation args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + struct d3dddi_allocationinfo2 *alloc_info =3D NULL; + struct d3dkmt_createstandardallocation standard_alloc; + u32 alloc_info_size =3D 0; + struct dxgresource *resource =3D NULL; + struct dxgallocation **dxgalloc =3D NULL; + bool resource_mutex_acquired =3D false; + u32 standard_alloc_priv_data_size =3D 0; + void *standard_alloc_priv_data =3D NULL; + u32 res_priv_data_size =3D 0; + void *res_priv_data =3D NULL; + int i; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.alloc_count > D3DKMT_CREATEALLOCATION_MAX || + args.alloc_count =3D=3D 0) { + DXG_ERR("invalid number of allocations to create"); + ret =3D -EINVAL; + goto cleanup; + } + + alloc_info_size =3D sizeof(struct d3dddi_allocationinfo2) * + args.alloc_count; + alloc_info =3D vzalloc(alloc_info_size); + if (alloc_info =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user(alloc_info, args.allocation_info, + alloc_info_size); + if (ret) { + DXG_ERR("failed to copy alloc info"); + ret =3D -EINVAL; + goto cleanup; + } + + for (i =3D 0; i < args.alloc_count; i++) { + if (args.flags.standard_allocation) { + if (alloc_info[i].priv_drv_data_size !=3D 0) { + DXG_ERR("private data size not zero"); + ret =3D -EINVAL; + goto cleanup; + } + } + if (alloc_info[i].priv_drv_data_size >=3D + DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("private data size too big: %d %d %ld", + i, alloc_info[i].priv_drv_data_size, + sizeof(alloc_info[0])); + ret =3D -EINVAL; + goto cleanup; + } + } + + if (args.flags.existing_section || args.flags.create_protected) { + DXG_ERR("invalid allocation flags"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.flags.standard_allocation) { + if (args.standard_allocation =3D=3D NULL) { + DXG_ERR("invalid standard allocation"); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D copy_from_user(&standard_alloc, + args.standard_allocation, + sizeof(standard_alloc)); + if (ret) { + DXG_ERR("failed to copy std alloc data"); + ret =3D -EINVAL; + goto cleanup; + } + if (standard_alloc.type =3D=3D + _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP) { + if (alloc_info[0].sysmem =3D=3D NULL || + (unsigned long)alloc_info[0].sysmem & + (PAGE_SIZE - 1)) { + DXG_ERR("invalid sysmem pointer"); + ret =3D STATUS_INVALID_PARAMETER; + goto cleanup; + } + if (!args.flags.existing_sysmem) { + DXG_ERR("expect existing_sysmem flag"); + ret =3D STATUS_INVALID_PARAMETER; + goto cleanup; + } + } else if (standard_alloc.type =3D=3D + _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER) { + if (args.flags.existing_sysmem) { + DXG_ERR("existing_sysmem flag invalid"); + ret =3D STATUS_INVALID_PARAMETER; + goto cleanup; + + } + if (alloc_info[0].sysmem !=3D NULL) { + DXG_ERR("sysmem should be NULL"); + ret =3D STATUS_INVALID_PARAMETER; + goto cleanup; + } + } else { + DXG_ERR("invalid standard allocation type"); + ret =3D STATUS_INVALID_PARAMETER; + goto cleanup; + } + + if (args.priv_drv_data_size !=3D 0 || + args.alloc_count !=3D 1 || + standard_alloc.existing_heap_data.size =3D=3D 0 || + standard_alloc.existing_heap_data.size & (PAGE_SIZE - 1)) { + DXG_ERR("invalid standard allocation"); + ret =3D -EINVAL; + goto cleanup; + } + args.priv_drv_data_size =3D + sizeof(struct d3dkmt_createstandardallocation); + } + + if (args.flags.create_shared && !args.flags.create_resource) { + DXG_ERR("create_resource must be set for create_shared"); + ret =3D -EINVAL; + goto cleanup; + } + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + if (args.flags.standard_allocation) { + ret =3D get_standard_alloc_priv_data(device, + &standard_alloc, + &standard_alloc_priv_data_size, + &standard_alloc_priv_data, + &res_priv_data_size, + &res_priv_data); + if (ret < 0) + goto cleanup; + DXG_TRACE("Alloc private data: %d", + standard_alloc_priv_data_size); + } + + if (args.flags.create_resource) { + resource =3D dxgresource_create(device); + if (resource =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + resource->private_runtime_handle =3D + args.private_runtime_resource_handle; + } else { + if (args.resource.v) { + /* Adding new allocations to the given resource */ + + dxgprocess_ht_lock_shared_down(process); + resource =3D hmgrtable_get_object_by_type( + &process->handle_table, + HMGRENTRY_TYPE_DXGRESOURCE, + args.resource); + kref_get(&resource->resource_kref); + dxgprocess_ht_lock_shared_up(process); + + if (resource =3D=3D NULL || resource->device !=3D device) { + DXG_ERR("invalid resource handle %x", + args.resource.v); + ret =3D -EINVAL; + goto cleanup; + } + /* Synchronize with resource destruction */ + mutex_lock(&resource->resource_mutex); + if (!dxgresource_is_active(resource)) { + mutex_unlock(&resource->resource_mutex); + ret =3D -EINVAL; + goto cleanup; + } + resource_mutex_acquired =3D true; + } + } + + dxgalloc =3D vzalloc(sizeof(struct dxgallocation *) * args.alloc_count); + if (dxgalloc =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + for (i =3D 0; i < args.alloc_count; i++) { + struct dxgallocation *alloc; + u32 priv_data_size; + + if (args.flags.standard_allocation) + priv_data_size =3D standard_alloc_priv_data_size; + else + priv_data_size =3D alloc_info[i].priv_drv_data_size; + + if (alloc_info[i].sysmem && !args.flags.standard_allocation) { + if ((unsigned long) + alloc_info[i].sysmem & (PAGE_SIZE - 1)) { + DXG_ERR("invalid sysmem alloc %d, %p", + i, alloc_info[i].sysmem); + ret =3D -EINVAL; + goto cleanup; + } + } + if ((alloc_info[0].sysmem =3D=3D NULL) !=3D + (alloc_info[i].sysmem =3D=3D NULL)) { + DXG_ERR("All allocs must have sysmem pointer"); + ret =3D -EINVAL; + goto cleanup; + } + + dxgalloc[i] =3D dxgallocation_create(process); + if (dxgalloc[i] =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + alloc =3D dxgalloc[i]; + + if (resource) { + ret =3D dxgresource_add_alloc(resource, alloc); + if (ret < 0) + goto cleanup; + } else { + dxgdevice_add_alloc(device, alloc); + } + if (args.flags.create_shared) { + /* Remember alloc private data to use it during open */ + alloc->priv_drv_data =3D vzalloc(priv_data_size + + offsetof(struct privdata, data)); + if (alloc->priv_drv_data =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + if (args.flags.standard_allocation) { + memcpy(alloc->priv_drv_data->data, + standard_alloc_priv_data, + priv_data_size); + } else { + ret =3D copy_from_user( + alloc->priv_drv_data->data, + alloc_info[i].priv_drv_data, + priv_data_size); + if (ret) { + dev_err(DXGDEV, + "failed to copy priv data"); + ret =3D -EFAULT; + goto cleanup; + } + } + alloc->priv_drv_data->data_size =3D priv_data_size; + } + } + + ret =3D dxgvmb_send_create_allocation(process, device, &args, inargs, + resource, dxgalloc, alloc_info, + &standard_alloc); +cleanup: + + if (resource_mutex_acquired) { + mutex_unlock(&resource->resource_mutex); + kref_put(&resource->resource_kref, dxgresource_release); + } + if (ret < 0) { + if (dxgalloc) { + for (i =3D 0; i < args.alloc_count; i++) { + if (dxgalloc[i]) + dxgallocation_destroy(dxgalloc[i]); + } + } + if (resource && args.flags.create_resource) { + dxgresource_destroy(resource); + } + } + if (dxgalloc) + vfree(dxgalloc); + if (standard_alloc_priv_data) + vfree(standard_alloc_priv_data); + if (res_priv_data) + vfree(res_priv_data); + if (alloc_info) + vfree(alloc_info); + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) { + dxgdevice_release_lock_shared(device); + kref_put(&device->device_kref, dxgdevice_release); + } + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int validate_alloc(struct dxgallocation *alloc0, + struct dxgallocation *alloc, + struct dxgdevice *device, + struct d3dkmthandle alloc_handle) +{ + u32 fail_reason; + + if (alloc =3D=3D NULL) { + fail_reason =3D 1; + goto cleanup; + } + if (alloc->resource_owner !=3D alloc0->resource_owner) { + fail_reason =3D 2; + goto cleanup; + } + if (alloc->resource_owner) { + if (alloc->owner.resource !=3D alloc0->owner.resource) { + fail_reason =3D 3; + goto cleanup; + } + if (alloc->owner.resource->device !=3D device) { + fail_reason =3D 4; + goto cleanup; + } + } else { + if (alloc->owner.device !=3D device) { + fail_reason =3D 6; + goto cleanup; + } + } + return 0; +cleanup: + DXG_ERR("Alloc validation failed: reason: %d %x", + fail_reason, alloc_handle.v); + return -EINVAL; +} + +static int +dxgkio_destroy_allocation(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_destroyallocation2 args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + int ret; + struct d3dkmthandle *alloc_handles =3D NULL; + struct dxgallocation **allocs =3D NULL; + struct dxgresource *resource =3D NULL; + int i; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.alloc_count > D3DKMT_CREATEALLOCATION_MAX || + ((args.alloc_count =3D=3D 0) =3D=3D (args.resource.v =3D=3D 0))) { + DXG_ERR("invalid number of allocations"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.alloc_count) { + u32 handle_size =3D sizeof(struct d3dkmthandle) * + args.alloc_count; + + alloc_handles =3D vzalloc(handle_size); + if (alloc_handles =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + allocs =3D vzalloc(sizeof(struct dxgallocation *) * + args.alloc_count); + if (allocs =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user(alloc_handles, args.allocations, + handle_size); + if (ret) { + DXG_ERR("failed to copy alloc handles"); + ret =3D -EINVAL; + goto cleanup; + } + } + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + /* Acquire the device lock to synchronize with the device destriction */ + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + /* + * Destroy the local allocation handles first. If the host handle + * is destroyed first, another object could be assigned to the process + * table at the same place as the allocation handle and it will fail. + */ + if (args.alloc_count) { + dxgprocess_ht_lock_exclusive_down(process); + for (i =3D 0; i < args.alloc_count; i++) { + allocs[i] =3D + hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGALLOCATION, + alloc_handles[i]); + ret =3D + validate_alloc(allocs[0], allocs[i], device, + alloc_handles[i]); + if (ret < 0) { + dxgprocess_ht_lock_exclusive_up(process); + goto cleanup; + } + } + dxgprocess_ht_lock_exclusive_up(process); + for (i =3D 0; i < args.alloc_count; i++) + dxgallocation_free_handle(allocs[i]); + } else { + struct dxgallocation *alloc; + + dxgprocess_ht_lock_exclusive_down(process); + resource =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGRESOURCE, + args.resource); + if (resource =3D=3D NULL) { + DXG_ERR("Invalid resource handle: %x", + args.resource.v); + ret =3D -EINVAL; + } else if (resource->device !=3D device) { + DXG_ERR("Resource belongs to wrong device: %x", + args.resource.v); + ret =3D -EINVAL; + } else { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGRESOURCE, + args.resource); + resource->object_state =3D DXGOBJECTSTATE_DESTROYED; + resource->handle.v =3D 0; + resource->handle_valid =3D 0; + } + dxgprocess_ht_lock_exclusive_up(process); + + if (ret < 0) + goto cleanup; + + dxgdevice_acquire_alloc_list_lock_shared(device); + list_for_each_entry(alloc, &resource->alloc_list_head, + alloc_list_entry) { + dxgallocation_free_handle(alloc); + } + dxgdevice_release_alloc_list_lock_shared(device); + } + + if (args.alloc_count && allocs[0]->resource_owner) + resource =3D allocs[0]->owner.resource; + + if (resource) { + kref_get(&resource->resource_kref); + mutex_lock(&resource->resource_mutex); + } + + ret =3D dxgvmb_send_destroy_allocation(process, device, &args, + alloc_handles); + + /* + * Destroy the allocations after the host destroyed it. + * The allocation gpadl teardown will wait until the host unmaps its + * gpadl. + */ + dxgdevice_acquire_alloc_list_lock(device); + if (args.alloc_count) { + for (i =3D 0; i < args.alloc_count; i++) { + if (allocs[i]) { + allocs[i]->alloc_handle.v =3D 0; + dxgallocation_destroy(allocs[i]); + } + } + } else { + dxgresource_destroy(resource); + } + dxgdevice_release_alloc_list_lock(device); + + if (resource) { + mutex_unlock(&resource->resource_mutex); + kref_put(&resource->resource_kref, dxgresource_release); + } + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) { + dxgdevice_release_lock_shared(device); + kref_put(&device->device_kref, dxgdevice_release); + } + + if (alloc_handles) + vfree(alloc_handles); + + if (allocs) + vfree(allocs); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static struct ioctl_desc ioctls[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -721,7 +1348,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x03 */ {}, /* 0x04 */ {dxgkio_create_context_virtual, LX_DXCREATECONTEXTVIRTUAL}, /* 0x05 */ {dxgkio_destroy_context, LX_DXDESTROYCONTEXT}, -/* 0x06 */ {}, +/* 0x06 */ {dxgkio_create_allocation, LX_DXCREATEALLOCATION}, /* 0x07 */ {}, /* 0x08 */ {}, /* 0x09 */ {dxgkio_query_adapter_info, LX_DXQUERYADAPTERINFO}, @@ -734,7 +1361,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x10 */ {}, /* 0x11 */ {}, /* 0x12 */ {}, -/* 0x13 */ {}, +/* 0x13 */ {dxgkio_destroy_allocation, LX_DXDESTROYALLOCATION2}, /* 0x14 */ {dxgkio_enum_adapters, LX_DXENUMADAPTERS2}, /* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER}, /* 0x16 */ {}, diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h index 3a9637f0b5e2..a51b29a6a68f 100644 --- a/drivers/hv/dxgkrnl/misc.h +++ b/drivers/hv/dxgkrnl/misc.h @@ -30,6 +30,9 @@ extern const struct d3dkmthandle zerohandle; * plistmutex (process list mutex) * table_lock (handle table lock) * context_list_lock + * alloc_list_lock + * resource_mutex + * shared_resource_list_lock * core_lock (dxgadapter lock) * device_lock (dxgdevice lock) * process_adapter_mutex diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 4ba0070b061f..cf670b9c4dc2 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -58,6 +58,7 @@ struct winluid { __u32 b; }; =20 +#define D3DKMT_CREATEALLOCATION_MAX 1024 #define D3DKMT_ADAPTERS_MAX 64 =20 struct d3dkmt_adapterinfo { @@ -197,6 +198,205 @@ struct d3dkmt_createcontextvirtual { struct d3dkmthandle context; }; =20 +enum d3dkmdt_gdisurfacetype { + _D3DKMDT_GDISURFACE_INVALID =3D 0, + _D3DKMDT_GDISURFACE_TEXTURE =3D 1, + _D3DKMDT_GDISURFACE_STAGING_CPUVISIBLE =3D 2, + _D3DKMDT_GDISURFACE_STAGING =3D 3, + _D3DKMDT_GDISURFACE_LOOKUPTABLE =3D 4, + _D3DKMDT_GDISURFACE_EXISTINGSYSMEM =3D 5, + _D3DKMDT_GDISURFACE_TEXTURE_CPUVISIBLE =3D 6, + _D3DKMDT_GDISURFACE_TEXTURE_CROSSADAPTER =3D 7, + _D3DKMDT_GDISURFACE_TEXTURE_CPUVISIBLE_CROSSADAPTER =3D 8, +}; + +struct d3dddi_rational { + __u32 numerator; + __u32 denominator; +}; + +enum d3dddiformat { + _D3DDDIFMT_UNKNOWN =3D 0, +}; + +struct d3dkmdt_gdisurfacedata { + __u32 width; + __u32 height; + __u32 format; + enum d3dkmdt_gdisurfacetype type; + __u32 flags; + __u32 pitch; +}; + +struct d3dkmdt_stagingsurfacedata { + __u32 width; + __u32 height; + __u32 pitch; +}; + +struct d3dkmdt_sharedprimarysurfacedata { + __u32 width; + __u32 height; + enum d3dddiformat format; + struct d3dddi_rational refresh_rate; + __u32 vidpn_source_id; +}; + +struct d3dkmdt_shadowsurfacedata { + __u32 width; + __u32 height; + enum d3dddiformat format; + __u32 pitch; +}; + +enum d3dkmdt_standardallocationtype { + _D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE =3D 1, + _D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE =3D 2, + _D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE =3D 3, + _D3DKMDT_STANDARDALLOCATION_GDISURFACE =3D 4, +}; + +enum d3dkmt_standardallocationtype { + _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP =3D 1, + _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER =3D 2, +}; + +struct d3dkmt_standardallocation_existingheap { + __u64 size; +}; + +struct d3dkmt_createstandardallocationflags { + union { + struct { + __u32 reserved:32; + }; + __u32 value; + }; +}; + +struct d3dkmt_createstandardallocation { + enum d3dkmt_standardallocationtype type; + __u32 reserved; + struct d3dkmt_standardallocation_existingheap existing_heap_data; + struct d3dkmt_createstandardallocationflags flags; + __u32 reserved1; +}; + +struct d3dddi_allocationinfo2 { + struct d3dkmthandle allocation; +#ifdef __KERNEL__ + const void *sysmem; +#else + __u64 sysmem; +#endif +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + __u32 priv_drv_data_size; + __u32 vidpn_source_id; + union { + struct { + __u32 primary:1; + __u32 stereo:1; + __u32 override_priority:1; + __u32 reserved:29; + }; + __u32 value; + } flags; + __u64 gpu_virtual_address; + union { + __u32 priority; + __u64 unused; + }; + __u64 reserved[5]; +}; + +struct d3dkmt_createallocationflags { + union { + struct { + __u32 create_resource:1; + __u32 create_shared:1; + __u32 non_secure:1; + __u32 create_protected:1; + __u32 restrict_shared_access:1; + __u32 existing_sysmem:1; + __u32 nt_security_sharing:1; + __u32 read_only:1; + __u32 create_write_combined:1; + __u32 create_cached:1; + __u32 swap_chain_back_buffer:1; + __u32 cross_adapter:1; + __u32 open_cross_adapter:1; + __u32 partial_shared_creation:1; + __u32 zeroed:1; + __u32 write_watch:1; + __u32 standard_allocation:1; + __u32 existing_section:1; + __u32 reserved:14; + }; + __u32 value; + }; +}; + +struct d3dkmt_createallocation { + struct d3dkmthandle device; + struct d3dkmthandle resource; + struct d3dkmthandle global_share; + __u32 reserved; +#ifdef __KERNEL__ + const void *private_runtime_data; +#else + __u64 private_runtime_data; +#endif + __u32 private_runtime_data_size; + __u32 reserved1; + union { +#ifdef __KERNEL__ + struct d3dkmt_createstandardallocation *standard_allocation; + const void *priv_drv_data; +#else + __u64 standard_allocation; + __u64 priv_drv_data; +#endif + }; + __u32 priv_drv_data_size; + __u32 alloc_count; +#ifdef __KERNEL__ + struct d3dddi_allocationinfo2 *allocation_info; +#else + __u64 allocation_info; +#endif + struct d3dkmt_createallocationflags flags; + __u32 reserved2; + __u64 private_runtime_resource_handle; +}; + +struct d3dddicb_destroyallocation2flags { + union { + struct { + __u32 assume_not_in_use:1; + __u32 synchronous_destroy:1; + __u32 reserved:29; + __u32 system_use_only:1; + }; + __u32 value; + }; +}; + +struct d3dkmt_destroyallocation2 { + struct d3dkmthandle device; + struct d3dkmthandle resource; +#ifdef __KERNEL__ + const struct d3dkmthandle *allocations; +#else + __u64 allocations; +#endif + __u32 alloc_count; + struct d3dddicb_destroyallocation2flags flags; +}; + struct d3dkmt_adaptertype { union { struct { @@ -279,8 +479,12 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x04, struct d3dkmt_createcontextvirtual) #define LX_DXDESTROYCONTEXT \ _IOWR(0x47, 0x05, struct d3dkmt_destroycontext) +#define LX_DXCREATEALLOCATION \ + _IOWR(0x47, 0x06, struct d3dkmt_createallocation) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) +#define LX_DXDESTROYALLOCATION2 \ + _IOWR(0x47, 0x13, struct d3dkmt_destroyallocation2) #define LX_DXENUMADAPTERS2 \ _IOWR(0x47, 0x14, struct d3dkmt_enumadapters2) #define LX_DXCLOSEADAPTER \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f47.google.com (mail-wm1-f47.google.com [209.85.128.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E4BA53F8DE3 for ; Thu, 19 Mar 2026 20:25:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951931; cv=none; b=LufmIKYtiSTuaVYQWL9ZGHiyGDW8moYGEvk4P+QSl5sN0PlWf4gPEGkniJRgkMzHXY4OjsA4aKnUH07a6kzobMB/HjfloCDZLUSGtoXKoC4lOq43NhWCWXNZa4enLKvDtUM1dJE+0CipMIQ+V8AJUH5E22er9JDM31zTNSlDYQ4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951931; c=relaxed/simple; bh=IqcUGpB2PtgVu6arzPygtpGtWVPPQZJgUoQW8arIol0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=N5gzMoIR/6iJ8eyjdTFT8ts/4iFtZqkWPOmE0AFkIF916CsS412bN2pwMFnrK8Tl5PgJTStrXGCj+121BJXuWC7IM8vEbE+1vf9+13NdYTtuuIZ1IEK+7WCpXcHCFWpYFWIrB86kAV5xdAW8DzArM12VrBC7Ix9aaVMy5sLcQ4o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ABAIKlnz; arc=none smtp.client-ip=209.85.128.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ABAIKlnz" Received: by mail-wm1-f47.google.com with SMTP id 5b1f17b1804b1-486fe2024a9so2879865e9.0 for ; Thu, 19 Mar 2026 13:25:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951924; x=1774556724; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ye1TIkHhwdICDOIgZUhwxe648xXV4IEZCAKFuIhIotg=; b=ABAIKlnzISTT15ZHqqMzqIO7bfibaVTb3lWpEh52OjZ6mG+caurZOFC7EYxYbsnega U5mf0UeLnQuGvKw7vhv6+Dt052+NSkUj5udTbWssxKG5Izd/A5uEbhbn6E/cP9o+ROqd l1aJsxOXbgGEMXWxdYoWoTp4xmjIREr7KeMdpD/iMouIHyioWbcApOIOjAVxG388ogSa f0P9FZQi+NGVHmISzgd/AUSNuAXqvvGmVLwVbiTTFDCcpo2/ZtuI8X1VgG783rdp/CU+ yaLVPtD0vo7nqv/8+lg5+e4i1zh4Efly5i7tOF0oATEinJQ2C6pe60YQMJDsZNvpbbze P7ZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951924; x=1774556724; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ye1TIkHhwdICDOIgZUhwxe648xXV4IEZCAKFuIhIotg=; b=mWwv1otOzIndxS/lL1zr2qSkAhhykx6zr3BVkigfyn/pmnlIiW54P/jeWi/J/WZR0n K/CoroXWbGkYf2/jbmaEa10qIedL8NBDgKvIP7E2eSJ9szD8IpKU8aOxVAs8sZ6g4Hx4 4LMoO2G4Ft8T7/lPQHj6LvfQLx+lRviMGJiQzLYni8cCrhKTjgZnhL264qQf2S0Tx1ds U3psklZBf68WlrCMY53S5u0m20bugXGokZUtXBcEOV7owShA4LLeIr10UFZoEN23Q9CO z5+MMnUmelAI6PNhwo8VLujO1EbcuwagBj7hAfJFWRQBe6dJNdx0x1Q8U0tTd+aT0HpU P3KA== X-Gm-Message-State: AOJu0Yzfcr1w0x9zEWjVUNajGh6ufMHi6qnxwQFAIfWFQemUi/9Eegnj AR13XShZv6SuvZXZsX2h2Ty9pVtCaQRxdUKuVK269aI2lRWlhhfOLvWN X-Gm-Gg: ATEYQzwkMSS4Ma1Nnvoi0CR5OVGwUVOJ1iDqkq5wl13XWCzAZTrGxYkt/fcNsy2vuoC TS224sw5UUQ4BgqHmXDUimP9ufX9Glv9DR9zjeEi0/egprHQuqX+7IWumNixWXPcDQLyLn6ELRj MOOsRWqam8643El27gRP9o/c7X8xdG+umBmfT0XRyuz/vpKuCbc/YZHMqtfRthYAXpDj817gn+U OmfSue6t2wjhkgnKuXRJLcCJ8Ii0Ou24K02UWQE+wOL/gu6rF8v4WMdO6t34hfvbKG6eXb/9SQo 19CjwNpldLH81VuxuxCp2upEZsudqijBBq89zlud0zV3R2muFACcCutLp2WQFUUttIfIpqTHoDh 6QBySDiS2M50PUcnk+HLpWxGBI+rq0n3KiZtRkqhaJ1BwehvNY+JSWVj2ltU7bDCGwZJH0HKSJ0 XB/leAMgoO16rc1oNp6sR+Cy6ErFaQmvn6Xzkej7OxNpjcOz3c X-Received: by 2002:a05:600c:1d0c:b0:483:6d4a:7e6d with SMTP id 5b1f17b1804b1-486fee2ff25mr6878185e9.30.1773951923676; Thu, 19 Mar 2026 13:25:23 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.22 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:23 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 09/55] drivers: hv: dxgkrnl: Creation of compute device sync objects Date: Thu, 19 Mar 2026 20:24:23 +0000 Message-ID: <20260319202509.63802-10-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls to create and destroy compute devicesync objects: - the LX_DXCREATESYNCHRONIZATIONOBJECT ioctl, - the LX_DXDESTROYSYNCHRONIZATIONOBJECT ioctl. Compute device synchronization objects are used to synchronize execution of compute device commands, which are queued to different execution contexts (dxgcontext objects). There are several types of sync objects (mutex, monitored fence, CPU event, fence). A "signal" or a "wait" operation could be queued to an execution context. Monitored fence sync objects are particular important. A monitored fence object has a fence value, which could be monitored by the compute device or by CPU. Therefore, a CPU virtual address is allocated during object creation to allow an application to read the fence value. dxg_map_iospace and dxg_unmap_iospace implement creation of the CPU virtual address. This is done as follow: - The host allocates a portion of the guest IO space, which is mapped to the actual fence value memory on the host - The host returns the guest IO space address to the guest - The guest allocates a CPU virtual address and updates page tables to point to the IO space address Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 184 ++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 80 +++++++++++++ drivers/hv/dxgkrnl/dxgmodule.c | 1 + drivers/hv/dxgkrnl/dxgprocess.c | 16 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 205 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 20 ++++ drivers/hv/dxgkrnl/ioctl.c | 130 +++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 95 +++++++++++++++ 8 files changed, 729 insertions(+), 2 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index 402caa81a5db..d2f2b96527e6 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -160,6 +160,24 @@ void dxgadapter_remove_process(struct dxgprocess_adapt= er *process_info) list_del(&process_info->adapter_process_list_entry); } =20 +void dxgadapter_add_syncobj(struct dxgadapter *adapter, + struct dxgsyncobject *object) +{ + down_write(&adapter->shared_resource_list_lock); + list_add_tail(&object->syncobj_list_entry, &adapter->syncobj_list_head); + up_write(&adapter->shared_resource_list_lock); +} + +void dxgadapter_remove_syncobj(struct dxgsyncobject *object) +{ + down_write(&object->adapter->shared_resource_list_lock); + if (object->syncobj_list_entry.next) { + list_del(&object->syncobj_list_entry); + object->syncobj_list_entry.next =3D NULL; + } + up_write(&object->adapter->shared_resource_list_lock); +} + int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter) { down_write(&adapter->core_lock); @@ -213,6 +231,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *a= dapter, init_rwsem(&device->context_list_lock); init_rwsem(&device->alloc_list_lock); INIT_LIST_HEAD(&device->pqueue_list_head); + INIT_LIST_HEAD(&device->syncobj_list_head); device->object_state =3D DXGOBJECTSTATE_CREATED; device->execution_state =3D _D3DKMT_DEVICEEXECUTION_ACTIVE; =20 @@ -228,6 +247,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *a= dapter, void dxgdevice_stop(struct dxgdevice *device) { struct dxgallocation *alloc; + struct dxgsyncobject *syncobj; =20 DXG_TRACE("Destroying device: %p", device); dxgdevice_acquire_alloc_list_lock(device); @@ -235,6 +255,14 @@ void dxgdevice_stop(struct dxgdevice *device) dxgallocation_stop(alloc); } dxgdevice_release_alloc_list_lock(device); + + hmgrtable_lock(&device->process->handle_table, DXGLOCK_EXCL); + list_for_each_entry(syncobj, &device->syncobj_list_head, + syncobj_list_entry) { + dxgsyncobject_stop(syncobj); + } + hmgrtable_unlock(&device->process->handle_table, DXGLOCK_EXCL); + DXG_TRACE("Device stopped: %p", device); } =20 void dxgdevice_mark_destroyed(struct dxgdevice *device) @@ -263,6 +291,20 @@ void dxgdevice_destroy(struct dxgdevice *device) =20 dxgdevice_acquire_alloc_list_lock(device); =20 + while (!list_empty(&device->syncobj_list_head)) { + struct dxgsyncobject *syncobj =3D + list_first_entry(&device->syncobj_list_head, + struct dxgsyncobject, + syncobj_list_entry); + list_del(&syncobj->syncobj_list_entry); + syncobj->syncobj_list_entry.next =3D NULL; + dxgdevice_release_alloc_list_lock(device); + + dxgsyncobject_destroy(process, syncobj); + + dxgdevice_acquire_alloc_list_lock(device); + } + { struct dxgallocation *alloc; struct dxgallocation *tmp; @@ -565,6 +607,30 @@ void dxgdevice_release(struct kref *refcount) kfree(device); } =20 +void dxgdevice_add_syncobj(struct dxgdevice *device, + struct dxgsyncobject *syncobj) +{ + dxgdevice_acquire_alloc_list_lock(device); + list_add_tail(&syncobj->syncobj_list_entry, &device->syncobj_list_head); + kref_get(&syncobj->syncobj_kref); + dxgdevice_release_alloc_list_lock(device); +} + +void dxgdevice_remove_syncobj(struct dxgsyncobject *entry) +{ + struct dxgdevice *device =3D entry->device; + + dxgdevice_acquire_alloc_list_lock(device); + if (entry->syncobj_list_entry.next) { + list_del(&entry->syncobj_list_entry); + entry->syncobj_list_entry.next =3D NULL; + kref_put(&entry->syncobj_kref, dxgsyncobject_release); + } + dxgdevice_release_alloc_list_lock(device); + kref_put(&device->device_kref, dxgdevice_release); + entry->device =3D NULL; +} + struct dxgcontext *dxgcontext_create(struct dxgdevice *device) { struct dxgcontext *context; @@ -812,3 +878,121 @@ void dxgprocess_adapter_remove_device(struct dxgdevic= e *device) } mutex_unlock(&device->adapter_info->device_list_mutex); } + +struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process, + struct dxgdevice *device, + struct dxgadapter *adapter, + enum + d3dddi_synchronizationobject_type + type, + struct + d3dddi_synchronizationobject_flags + flags) +{ + struct dxgsyncobject *syncobj; + + syncobj =3D kzalloc(sizeof(*syncobj), GFP_KERNEL); + if (syncobj =3D=3D NULL) + goto cleanup; + syncobj->type =3D type; + syncobj->process =3D process; + switch (type) { + case _D3DDDI_MONITORED_FENCE: + case _D3DDDI_PERIODIC_MONITORED_FENCE: + syncobj->monitored_fence =3D 1; + break; + default: + break; + } + if (flags.shared) { + syncobj->shared =3D 1; + if (!flags.nt_security_sharing) { + DXG_ERR("nt_security_sharing must be set"); + goto cleanup; + } + } + + kref_init(&syncobj->syncobj_kref); + + if (syncobj->monitored_fence) { + syncobj->device =3D device; + syncobj->device_handle =3D device->handle; + kref_get(&device->device_kref); + dxgdevice_add_syncobj(device, syncobj); + } else { + dxgadapter_add_syncobj(adapter, syncobj); + } + syncobj->adapter =3D adapter; + kref_get(&adapter->adapter_kref); + + DXG_TRACE("Syncobj created: %p", syncobj); + return syncobj; +cleanup: + if (syncobj) + kfree(syncobj); + return NULL; +} + +void dxgsyncobject_destroy(struct dxgprocess *process, + struct dxgsyncobject *syncobj) +{ + int destroyed; + + DXG_TRACE("Destroying syncobj: %p", syncobj); + + dxgsyncobject_stop(syncobj); + + destroyed =3D test_and_set_bit(0, &syncobj->flags); + if (!destroyed) { + DXG_TRACE("Deleting handle: %x", syncobj->handle.v); + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + if (syncobj->handle.v) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + syncobj->handle); + syncobj->handle.v =3D 0; + kref_put(&syncobj->syncobj_kref, dxgsyncobject_release); + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (syncobj->monitored_fence) + dxgdevice_remove_syncobj(syncobj); + else + dxgadapter_remove_syncobj(syncobj); + if (syncobj->adapter) { + kref_put(&syncobj->adapter->adapter_kref, + dxgadapter_release); + syncobj->adapter =3D NULL; + } + } + kref_put(&syncobj->syncobj_kref, dxgsyncobject_release); +} + +void dxgsyncobject_stop(struct dxgsyncobject *syncobj) +{ + int stopped =3D test_and_set_bit(1, &syncobj->flags); + + if (!stopped) { + DXG_TRACE("Stopping syncobj"); + if (syncobj->monitored_fence) { + if (syncobj->mapped_address) { + int ret =3D + dxg_unmap_iospace(syncobj->mapped_address, + PAGE_SIZE); + + (void)ret; + DXG_TRACE("unmap fence %d %p", + ret, syncobj->mapped_address); + syncobj->mapped_address =3D NULL; + } + } + } +} + +void dxgsyncobject_release(struct kref *refcount) +{ + struct dxgsyncobject *syncobj; + + syncobj =3D container_of(refcount, struct dxgsyncobject, syncobj_kref); + kfree(syncobj); +} diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index fa053fb6ac9c..1b9410c9152b 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -38,6 +38,7 @@ struct dxgdevice; struct dxgcontext; struct dxgallocation; struct dxgresource; +struct dxgsyncobject; =20 /* * Driver private data. @@ -100,6 +101,56 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, s= truct hv_device *hdev); void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch); void dxgvmbuschannel_receive(void *ctx); =20 +/* + * This is GPU synchronization object, which is used to synchronize execut= ion + * between GPU contextx/hardware queues or for tracking GPU execution prog= ress. + * A dxgsyncobject is created when somebody creates a syncobject or opens a + * shared syncobject. + * A syncobject belongs to an adapter, unless it is a cross-adapter object. + * Cross adapter syncobjects are currently not implemented. + * + * D3DDDI_MONITORED_FENCE and D3DDDI_PERIODIC_MONITORED_FENCE are called + * "device" syncobject, because the belong to a device (dxgdevice). + * Device syncobjects are inserted to a list in dxgdevice. + * + */ +struct dxgsyncobject { + struct kref syncobj_kref; + enum d3dddi_synchronizationobject_type type; + /* + * List entry in dxgdevice for device sync objects. + * List entry in dxgadapter for other objects + */ + struct list_head syncobj_list_entry; + /* Adapter, the syncobject belongs to. NULL for stopped sync obejcts. */ + struct dxgadapter *adapter; + /* + * Pointer to the device, which was used to create the object. + * This is NULL for non-device syncbjects + */ + struct dxgdevice *device; + struct dxgprocess *process; + /* CPU virtual address of the fence value for "device" syncobjects */ + void *mapped_address; + /* Handle in the process handle table */ + struct d3dkmthandle handle; + /* Cached handle of the device. Used to avoid device dereference. */ + struct d3dkmthandle device_handle; + union { + struct { + /* Must be the first bit */ + u32 destroyed:1; + /* Must be the second bit */ + u32 stopped:1; + /* device syncobject */ + u32 monitored_fence:1; + u32 shared:1; + u32 reserved:27; + }; + long flags; + }; +}; + /* * The structure defines an offered vGPU vm bus channel. */ @@ -109,6 +160,20 @@ struct dxgvgpuchannel { struct hv_device *hdev; }; =20 +struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process, + struct dxgdevice *device, + struct dxgadapter *adapter, + enum + d3dddi_synchronizationobject_type + type, + struct + d3dddi_synchronizationobject_flags + flags); +void dxgsyncobject_destroy(struct dxgprocess *process, + struct dxgsyncobject *syncobj); +void dxgsyncobject_stop(struct dxgsyncobject *syncobj); +void dxgsyncobject_release(struct kref *refcount); + struct dxgglobal { struct dxgdriver *drvdata; struct dxgvmbuschannel channel; @@ -271,6 +336,8 @@ struct dxgadapter { struct list_head adapter_list_entry; /* The list of dxgprocess_adapter entries */ struct list_head adapter_process_list_head; + /* List of all non-device dxgsyncobject objects */ + struct list_head syncobj_list_head; /* This lock protects shared resource and syncobject lists */ struct rw_semaphore shared_resource_list_lock; struct pci_dev *pci_dev; @@ -296,6 +363,9 @@ void dxgadapter_release_lock_shared(struct dxgadapter *= adapter); int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter); void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter); void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter); +void dxgadapter_add_syncobj(struct dxgadapter *adapter, + struct dxgsyncobject *so); +void dxgadapter_remove_syncobj(struct dxgsyncobject *so); void dxgadapter_add_process(struct dxgadapter *adapter, struct dxgprocess_adapter *process_info); void dxgadapter_remove_process(struct dxgprocess_adapter *process_info); @@ -325,6 +395,7 @@ struct dxgdevice { struct list_head resource_list_head; /* List of paging queues. Protected by process handle table lock. */ struct list_head pqueue_list_head; + struct list_head syncobj_list_head; struct d3dkmthandle handle; enum d3dkmt_deviceexecution_state execution_state; u32 handle_valid; @@ -345,6 +416,8 @@ void dxgdevice_remove_alloc_safe(struct dxgdevice *dev, struct dxgallocation *a); void dxgdevice_add_resource(struct dxgdevice *dev, struct dxgresource *res= ); void dxgdevice_remove_resource(struct dxgdevice *dev, struct dxgresource *= res); +void dxgdevice_add_syncobj(struct dxgdevice *dev, struct dxgsyncobject *so= ); +void dxgdevice_remove_syncobj(struct dxgsyncobject *so); bool dxgdevice_is_active(struct dxgdevice *dev); void dxgdevice_acquire_context_list_lock(struct dxgdevice *dev); void dxgdevice_release_context_list_lock(struct dxgdevice *dev); @@ -455,6 +528,7 @@ void dxgallocation_free_handle(struct dxgallocation *a); long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2); long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2= ); =20 +int dxg_unmap_iospace(void *va, u32 size); /* * The convention is that VNBus instance id is a GUID, but the host sets * the lower part of the value to the host adapter LUID. The function @@ -514,6 +588,12 @@ int dxgvmb_send_create_allocation(struct dxgprocess *p= r, 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_create_sync_object(struct dxgprocess *pr, + struct dxgadapter *adapter, + struct d3dkmt_createsynchronizationobject2 + *args, struct dxgsyncobject *so); +int dxgvmb_send_destroy_sync_object(struct dxgprocess *pr, + struct d3dkmthandle h); int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 053ce6f3e083..9bc8931c5043 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -162,6 +162,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_= t *guid, init_rwsem(&adapter->core_lock); =20 INIT_LIST_HEAD(&adapter->adapter_process_list_head); + INIT_LIST_HEAD(&adapter->syncobj_list_head); init_rwsem(&adapter->shared_resource_list_lock); adapter->pci_dev =3D dev; guid_to_luid(guid, &adapter->luid); diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.c index ca307beb9a9a..a41985ef438d 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -59,6 +59,7 @@ void dxgprocess_destroy(struct dxgprocess *process) enum hmgrentry_type t; struct d3dkmthandle h; void *o; + struct dxgsyncobject *syncobj; struct dxgprocess_adapter *entry; struct dxgprocess_adapter *tmp; =20 @@ -84,6 +85,21 @@ void dxgprocess_destroy(struct dxgprocess *process) } } =20 + i =3D 0; + while (hmgrtable_next_entry(&process->handle_table, &i, &t, &h, &o)) { + switch (t) { + case HMGRENTRY_TYPE_DXGSYNCOBJECT: + DXG_TRACE("Destroy syncobj: %p %d", o, i); + syncobj =3D o; + syncobj->handle.v =3D 0; + dxgsyncobject_destroy(process, syncobj); + break; + default: + DXG_ERR("invalid entry in handle table %d", t); + break; + } + } + hmgrtable_destroy(&process->handle_table); hmgrtable_destroy(&process->local_handle_table); } diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 14b51a3c6afc..d323afc85249 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -495,6 +495,88 @@ dxgvmb_send_sync_msg_ntstatus(struct dxgvmbuschannel *= channel, return ret; } =20 +static int check_iospace_address(unsigned long address, u32 size) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (address < dxgglobal->mmiospace_base || + size > dxgglobal->mmiospace_size || + address >=3D (dxgglobal->mmiospace_base + + dxgglobal->mmiospace_size - size)) { + DXG_ERR("invalid iospace address %lx", address); + return -EINVAL; + } + return 0; +} + +int dxg_unmap_iospace(void *va, u32 size) +{ + int ret =3D 0; + + DXG_TRACE("Unmapping io space: %p %x", va, size); + + /* + * When an app calls exit(), dxgkrnl is called to close the device + * with current->mm equal to NULL. + */ + if (current->mm) { + ret =3D vm_munmap((unsigned long)va, size); + if (ret) { + DXG_ERR("vm_munmap failed %d", ret); + return -ENOTRECOVERABLE; + } + } + return 0; +} + +static u8 *dxg_map_iospace(u64 iospace_address, u32 size, + unsigned long protection, bool cached) +{ + struct vm_area_struct *vma; + unsigned long va; + int ret =3D 0; + + DXG_TRACE("Mapping io space: %llx %x %lx", + iospace_address, size, protection); + if (check_iospace_address(iospace_address, size) < 0) { + DXG_ERR("invalid address to map"); + return NULL; + } + + va =3D vm_mmap(NULL, 0, size, protection, MAP_SHARED | MAP_ANONYMOUS, 0); + if ((long)va <=3D 0) { + DXG_ERR("vm_mmap failed %lx %d", va, size); + return NULL; + } + + mmap_read_lock(current->mm); + vma =3D find_vma(current->mm, (unsigned long)va); + if (vma) { + pgprot_t prot =3D vma->vm_page_prot; + + if (!cached) + prot =3D pgprot_writecombine(prot); + DXG_TRACE("vma: %lx %lx %lx", + vma->vm_start, vma->vm_end, va); + vma->vm_pgoff =3D iospace_address >> PAGE_SHIFT; + ret =3D io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + size, prot); + if (ret) + DXG_ERR("io_remap_pfn_range failed: %d", ret); + } else { + DXG_ERR("failed to find vma: %p %lx", vma, va); + ret =3D -ENOMEM; + } + mmap_read_unlock(current->mm); + + if (ret) { + dxg_unmap_iospace((void *)va, size); + return NULL; + } + DXG_TRACE("Mapped VA: %lx", va); + return (u8 *) va; +} + /* * Global messages to the host */ @@ -613,6 +695,39 @@ int dxgvmb_send_destroy_process(struct d3dkmthandle pr= ocess) return ret; } =20 +int dxgvmb_send_destroy_sync_object(struct dxgprocess *process, + struct d3dkmthandle sync_object) +{ + struct dxgkvmb_command_destroysyncobject *command; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, NULL, process, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + command_vm_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_DESTROYSYNCOBJECT, + process->host_handle); + command->sync_object =3D sync_object; + + ret =3D dxgvmb_send_sync_msg_ntstatus(dxgglobal_get_dxgvmbuschannel(), + msg.hdr, msg.size); + + dxgglobal_release_channel_lock(); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + /* * Virtual GPU messages to the host */ @@ -1023,7 +1138,11 @@ int create_existing_sysmem(struct dxgdevice *device, ret =3D -ENOMEM; goto cleanup; } +#ifdef _MAIN_KERNEL_ DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle); +#else + DXG_TRACE("New gpadl %d", dxgalloc->gpadl); +#endif =20 command_vgpu_to_host_init2(&set_store_command->hdr, DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE, @@ -1501,6 +1620,92 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *= device, return ret; } =20 +static void set_result(struct d3dkmt_createsynchronizationobject2 *args, + u64 fence_gpu_va, u8 *va) +{ + args->info.periodic_monitored_fence.fence_gpu_virtual_address =3D + fence_gpu_va; + args->info.periodic_monitored_fence.fence_cpu_virtual_address =3D va; +} + +int +dxgvmb_send_create_sync_object(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_createsynchronizationobject2 *args, + struct dxgsyncobject *syncobj) +{ + struct dxgkvmb_command_createsyncobject_return result =3D { }; + struct dxgkvmb_command_createsyncobject *command; + int ret; + u8 *va =3D 0; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_CREATESYNCOBJECT, + process->host_handle); + command->args =3D *args; + command->client_hint =3D 1; /* CLIENTHINT_UMD */ + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result, + sizeof(result)); + if (ret < 0) { + DXG_ERR("failed %d", ret); + goto cleanup; + } + args->sync_object =3D result.sync_object; + if (syncobj->shared) { + if (result.global_sync_object.v =3D=3D 0) { + DXG_ERR("shared handle is 0"); + ret =3D -EINVAL; + goto cleanup; + } + args->info.shared_handle =3D result.global_sync_object; + } + + if (syncobj->monitored_fence) { + va =3D dxg_map_iospace(result.fence_storage_address, PAGE_SIZE, + PROT_READ | PROT_WRITE, true); + if (va =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + if (args->info.type =3D=3D _D3DDDI_MONITORED_FENCE) { + args->info.monitored_fence.fence_gpu_virtual_address =3D + result.fence_gpu_va; + args->info.monitored_fence.fence_cpu_virtual_address =3D + va; + { + unsigned long value; + + DXG_TRACE("fence cpu va: %p", va); + ret =3D copy_from_user(&value, va, + sizeof(u64)); + if (ret) { + DXG_ERR("failed to read fence"); + ret =3D -EINVAL; + } else { + DXG_TRACE("fence value:%lx", + value); + } + } + } else { + set_result(args, result.fence_gpu_va, va); + } + syncobj->mapped_address =3D va; + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 4b7466d1b9f2..bbf5f31cdf81 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -410,4 +410,24 @@ struct dxgkvmb_command_destroycontext { struct d3dkmthandle context; }; =20 +struct dxgkvmb_command_createsyncobject { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_createsynchronizationobject2 args; + u32 client_hint; +}; + +struct dxgkvmb_command_createsyncobject_return { + struct d3dkmthandle sync_object; + struct d3dkmthandle global_sync_object; + u64 fence_gpu_va; + u64 fence_storage_address; + u32 fence_storage_offset; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroysyncobject { + struct dxgkvmb_command_vm_to_host hdr; + struct d3dkmthandle sync_object; +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 0eaa577d7ed4..4bba1e209f33 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -1341,6 +1341,132 @@ dxgkio_destroy_allocation(struct dxgprocess *proces= s, void *__user inargs) return ret; } =20 +static int +dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs) +{ + int ret; + struct d3dkmt_createsynchronizationobject2 args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct dxgsyncobject *syncobj =3D NULL; + bool device_lock_acquired =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) + goto cleanup; + + device_lock_acquired =3D true; + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + syncobj =3D dxgsyncobject_create(process, device, adapter, args.info.type, + args.info.flags); + if (syncobj =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgvmb_send_create_sync_object(process, adapter, &args, syncobj); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy output args"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(&process->handle_table, syncobj, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + args.sync_object); + if (ret >=3D 0) + syncobj->handle =3D args.sync_object; + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + +cleanup: + + if (ret < 0) { + if (syncobj) { + dxgsyncobject_destroy(process, syncobj); + if (args.sync_object.v) + dxgvmb_send_destroy_sync_object(process, + args.sync_object); + } + } + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device_lock_acquired) + dxgdevice_release_lock_shared(device); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_destroy_sync_object(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_destroysynchronizationobject args; + struct dxgsyncobject *syncobj =3D NULL; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + DXG_TRACE("handle 0x%x", args.sync_object.v); + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + syncobj =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + args.sync_object); + if (syncobj) { + DXG_TRACE("syncobj 0x%p", syncobj); + syncobj->handle.v =3D 0; + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + args.sync_object); + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (syncobj =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + dxgsyncobject_destroy(process, syncobj); + + ret =3D dxgvmb_send_destroy_sync_object(process, args.sync_object); + +cleanup: + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static struct ioctl_desc ioctls[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -1358,7 +1484,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x0d */ {}, /* 0x0e */ {}, /* 0x0f */ {}, -/* 0x10 */ {}, +/* 0x10 */ {dxgkio_create_sync_object, LX_DXCREATESYNCHRONIZATIONOBJECT}, /* 0x11 */ {}, /* 0x12 */ {}, /* 0x13 */ {dxgkio_destroy_allocation, LX_DXDESTROYALLOCATION2}, @@ -1371,7 +1497,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x1a */ {}, /* 0x1b */ {}, /* 0x1c */ {}, -/* 0x1d */ {}, +/* 0x1d */ {dxgkio_destroy_sync_object, LX_DXDESTROYSYNCHRONIZATIONOBJECT}, /* 0x1e */ {}, /* 0x1f */ {}, /* 0x20 */ {}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index cf670b9c4dc2..4e1069f41d76 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -256,6 +256,97 @@ enum d3dkmdt_standardallocationtype { _D3DKMDT_STANDARDALLOCATION_GDISURFACE =3D 4, }; =20 +struct d3dddi_synchronizationobject_flags { + union { + struct { + __u32 shared:1; + __u32 nt_security_sharing:1; + __u32 cross_adapter:1; + __u32 top_of_pipeline:1; + __u32 no_signal:1; + __u32 no_wait:1; + __u32 no_signal_max_value_on_tdr:1; + __u32 no_gpu_access:1; + __u32 reserved:23; + }; + __u32 value; + }; +}; + +enum d3dddi_synchronizationobject_type { + _D3DDDI_SYNCHRONIZATION_MUTEX =3D 1, + _D3DDDI_SEMAPHORE =3D 2, + _D3DDDI_FENCE =3D 3, + _D3DDDI_CPU_NOTIFICATION =3D 4, + _D3DDDI_MONITORED_FENCE =3D 5, + _D3DDDI_PERIODIC_MONITORED_FENCE =3D 6, + _D3DDDI_SYNCHRONIZATION_TYPE_LIMIT +}; + +struct d3dddi_synchronizationobjectinfo2 { + enum d3dddi_synchronizationobject_type type; + struct d3dddi_synchronizationobject_flags flags; + union { + struct { + __u32 initial_state; + } synchronization_mutex; + + struct { + __u32 max_count; + __u32 initial_count; + } semaphore; + + struct { + __u64 fence_value; + } fence; + + struct { + __u64 event; + } cpu_notification; + + struct { + __u64 initial_fence_value; +#ifdef __KERNEL__ + void *fence_cpu_virtual_address; +#else + __u64 *fence_cpu_virtual_address; +#endif + __u64 fence_gpu_virtual_address; + __u32 engine_affinity; + } monitored_fence; + + struct { + struct d3dkmthandle adapter; + __u32 vidpn_target_id; + __u64 time; +#ifdef __KERNEL__ + void *fence_cpu_virtual_address; +#else + __u64 fence_cpu_virtual_address; +#endif + __u64 fence_gpu_virtual_address; + __u32 engine_affinity; + } periodic_monitored_fence; + + struct { + __u64 reserved[8]; + } reserved; + }; + struct d3dkmthandle shared_handle; +}; + +struct d3dkmt_createsynchronizationobject2 { + struct d3dkmthandle device; + __u32 reserved; + struct d3dddi_synchronizationobjectinfo2 info; + struct d3dkmthandle sync_object; + __u32 reserved1; +}; + +struct d3dkmt_destroysynchronizationobject { + struct d3dkmthandle sync_object; +}; + enum d3dkmt_standardallocationtype { _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP =3D 1, _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER =3D 2, @@ -483,6 +574,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x06, struct d3dkmt_createallocation) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) +#define LX_DXCREATESYNCHRONIZATIONOBJECT \ + _IOWR(0x47, 0x10, struct d3dkmt_createsynchronizationobject2) #define LX_DXDESTROYALLOCATION2 \ _IOWR(0x47, 0x13, struct d3dkmt_destroyallocation2) #define LX_DXENUMADAPTERS2 \ @@ -491,6 +584,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x15, struct d3dkmt_closeadapter) #define LX_DXDESTROYDEVICE \ _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) +#define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ + _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) #define LX_DXENUMADAPTERS3 \ _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D40E63F8DFE for ; Thu, 19 Mar 2026 20:25:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951933; cv=none; b=cZTobkjtPMHcB3ytHvhb6gW0q/nEMcDPtXtOqa38VDCIn4uTSmZbleOJuFy4jsS1/phzbfKqM8UaSul4phOh3/RiZZKW7+WIKqln5tddep+CLotXynXiSJrBb5PevIr/WpT2+7yQPEMTipkootonGZw4i0/wtwcvCWA/fpOKCds= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951933; c=relaxed/simple; bh=hWaj+AbCeBNBzpSrBAnvA3jXWYGw1oajIc2ZhnDA5gU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W+b8bGKNovLlgod+H4oxzRvidr5QfjbF5gvtNG2swZSrqgVUKTZaIEeD5Q2DbZjY1KIzc6G0QZl+gkAs7ggNz03vPQQ+TjS0EAzrcI2ec/Vt0cPhx7B1GeZTiKFlMqd3Fh0coRtkTP3AlntgFiSEZmp4t5eYHPdFQAAbychwHq8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=RWrAezpo; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RWrAezpo" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-48538c5956bso12090025e9.0 for ; Thu, 19 Mar 2026 13:25:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951925; x=1774556725; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Imh3pQm0rMLrtjrreshsOxO8Wpd5bNe9RVmIt++dIYs=; b=RWrAezpoI7twyJq9n0uiF7zTEVCFd7BF5QQGj2lh9RLl9LnF1XNhFaTGiiasQcCzsb 5NXisn4bpCLQgrw/6w/XqgNGyXox8qozNY2eXOQKEMcNbQNBvKg8IrO4dCmsa5Buxbei tOdii3SAv5KPIOUUg21cfSnZcyApBNhvYqdzi4qjtZsbnbK85dOQc5PJsvNJI2Gt+XCx 9Y7q9/bzHKmZav49ExZbxDPWH5fXl/zfu9zjnmtqUd1UXIht99NhF2Orn1yP2ldFOaNb 1jcpEzqdyNEdWtxu7GhnbNGNbf7LKyEoSbcTx15/MFCMYG7jbExwHX8NQyBnutuQ/Fzz sDvg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951925; x=1774556725; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Imh3pQm0rMLrtjrreshsOxO8Wpd5bNe9RVmIt++dIYs=; b=g36ynaxAvjn1ODb5s1RcD5cuqUEedpfW6DDE/WE8lNRwXyiI6lo3VQa/+QwOnu6pZs gXk0fdFnk8uEtnkaSJfBCKHvIT/INEIzhrfl1ZKg5jK0EYvCoR6RPwP+YhFrfwCcE2Fz Twdc4/pGiVVinNEJWE3lJYtzoL/nWuPRhbALoEzkHXKnfhi2Z1nODqBrDcTFvJieHeZt ZurrCh8IstUjHCeGgAIJ+NR2ic2UUfOB70lRcb4Vlc2f55AqWKvwWj5rSUTWenpkDmE0 uMq5ImTrOeAPUMFo4Ps5oIcxUmknz7301cNq7v+hZzMxqzlUufKQOdSi+1Um5u4GrIT8 xd+Q== X-Gm-Message-State: AOJu0YxJMIkz767DMVfIzOUH0iBdOKmnKNAkxqkBy9ukdGzFW5FlRPV7 Q/G+iP9xlL17GsEOES/1FbjKkrCK5J7GRRZsCwLlV7U5Sf8VvZV8161A X-Gm-Gg: ATEYQzwaRCmkB/M6FqV9HsdAXH+C8PhGKINPQ1G/fveL1Bui6159QCDJWcfPIX38YFF W4Sbh6SgM17Tdl9dOv0AIpUrMioDP/n8COJXIZwvLA+Nkotjr2N67U6eaP7n8MfSoap5Rf2459d 9iaR4mbyJGS/eus99tJGmJgQooxqvYp4Qg4NJRLH5Q6S836+FLknwzZ0SKZx7yi3eNZpLHfSI1/ DWdWiDD8vpC9M353pKsrUe540K4WuJV57OP8m//dX+8qY1Jx0uBpHTtLy2KBJqtl85nPtJsL57j InZrMiq/XNqBsbEfVIRA7r9baVnhiwJ7dfsUYeoNREYXGToRCAYRfn07edEIJrJEhq3CpvXJAC5 ng9MxYeGDTXgE9VxI7Nw7hvXdfPs8k35bbOPoApkc8jRkNvv4OG3PJRJC7b+oWc65xry28CxsiZ Pu7s9hmrBV5o8cuM4rCdc5o+vEEpwJdQt7U4+tmLHh84YstRdC X-Received: by 2002:a05:600c:8883:b0:486:feb7:f2a with SMTP id 5b1f17b1804b1-486feb70f41mr6174705e9.13.1773951924783; Thu, 19 Mar 2026 13:25:24 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.23 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:24 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 10/55] drivers: hv: dxgkrnl: Operations using sync objects Date: Thu, 19 Mar 2026 20:24:24 +0000 Message-ID: <20260319202509.63802-11-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls to submit operations with compute device sync objects: - the LX_DXSIGNALSYNCHRONIZATIONOBJECT ioctl. The ioctl is used to submit a signal to a sync object. - the LX_DXWAITFORSYNCHRONIZATIONOBJECT ioctl. The ioctl is used to submit a wait for a sync object - the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU ioctl The ioctl is used to signal to a monitored fence sync object from a CPU thread. - the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU ioctl. The ioctl is used to submit a signal to a monitored fence sync object.. - the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2 ioctl. The ioctl is used to submit a signal to a monitored fence sync object. - the LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU ioctl. The ioctl is used to submit a wait for a monitored fence sync object. Compute device synchronization objects are used to synchronize execution of DMA buffers between different execution contexts. Operations with sync objects include "signal" and "wait". A wait for a sync object is satisfied when the sync object is signaled. A signal operation could be submitted to a compute device context or the sync object could be signaled by a CPU thread. To improve performance, submitting operations to the host is done asynchronously when the host supports it. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 38 +- drivers/hv/dxgkrnl/dxgkrnl.h | 62 +++ drivers/hv/dxgkrnl/dxgmodule.c | 102 ++++- drivers/hv/dxgkrnl/dxgvmbus.c | 219 +++++++++- drivers/hv/dxgkrnl/dxgvmbus.h | 48 +++ drivers/hv/dxgkrnl/ioctl.c | 702 +++++++++++++++++++++++++++++++- drivers/hv/dxgkrnl/misc.h | 2 + include/uapi/misc/d3dkmthk.h | 159 ++++++++ 8 files changed, 1311 insertions(+), 21 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index d2f2b96527e6..04d827a15c54 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -249,7 +249,7 @@ void dxgdevice_stop(struct dxgdevice *device) struct dxgallocation *alloc; struct dxgsyncobject *syncobj; =20 - DXG_TRACE("Destroying device: %p", device); + DXG_TRACE("Stopping device: %p", device); dxgdevice_acquire_alloc_list_lock(device); list_for_each_entry(alloc, &device->alloc_list_head, alloc_list_entry) { dxgallocation_stop(alloc); @@ -743,15 +743,13 @@ void dxgallocation_destroy(struct dxgallocation *allo= c) } #ifdef _MAIN_KERNEL_ if (alloc->gpadl.gpadl_handle) { - DXG_TRACE("Teardown gpadl %d", - alloc->gpadl.gpadl_handle); + DXG_TRACE("Teardown gpadl %d", alloc->gpadl.gpadl_handle); vmbus_teardown_gpadl(dxgglobal_get_vmbus(), &alloc->gpadl); alloc->gpadl.gpadl_handle =3D 0; } else if (alloc->gpadl) { - DXG_TRACE("Teardown gpadl %d", - alloc->gpadl); + DXG_TRACE("Teardown gpadl %d", alloc->gpadl); vmbus_teardown_gpadl(dxgglobal_get_vmbus(), alloc->gpadl); alloc->gpadl =3D 0; } @@ -901,6 +899,13 @@ struct dxgsyncobject *dxgsyncobject_create(struct dxgp= rocess *process, case _D3DDDI_PERIODIC_MONITORED_FENCE: syncobj->monitored_fence =3D 1; break; + case _D3DDDI_CPU_NOTIFICATION: + syncobj->cpu_event =3D 1; + syncobj->host_event =3D kzalloc(sizeof(*syncobj->host_event), + GFP_KERNEL); + if (syncobj->host_event =3D=3D NULL) + goto cleanup; + break; default: break; } @@ -928,6 +933,8 @@ struct dxgsyncobject *dxgsyncobject_create(struct dxgpr= ocess *process, DXG_TRACE("Syncobj created: %p", syncobj); return syncobj; cleanup: + if (syncobj->host_event) + kfree(syncobj->host_event); if (syncobj) kfree(syncobj); return NULL; @@ -937,6 +944,7 @@ void dxgsyncobject_destroy(struct dxgprocess *process, struct dxgsyncobject *syncobj) { int destroyed; + struct dxghosteventcpu *host_event; =20 DXG_TRACE("Destroying syncobj: %p", syncobj); =20 @@ -955,6 +963,16 @@ void dxgsyncobject_destroy(struct dxgprocess *process, } hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); =20 + if (syncobj->cpu_event) { + host_event =3D syncobj->host_event; + if (host_event->cpu_event) { + eventfd_ctx_put(host_event->cpu_event); + if (host_event->hdr.event_id) + dxgglobal_remove_host_event( + &host_event->hdr); + host_event->cpu_event =3D NULL; + } + } if (syncobj->monitored_fence) dxgdevice_remove_syncobj(syncobj); else @@ -971,16 +989,14 @@ void dxgsyncobject_destroy(struct dxgprocess *process, void dxgsyncobject_stop(struct dxgsyncobject *syncobj) { int stopped =3D test_and_set_bit(1, &syncobj->flags); + int ret; =20 if (!stopped) { DXG_TRACE("Stopping syncobj"); if (syncobj->monitored_fence) { if (syncobj->mapped_address) { - int ret =3D - dxg_unmap_iospace(syncobj->mapped_address, - PAGE_SIZE); - - (void)ret; + ret =3D dxg_unmap_iospace(syncobj->mapped_address, + PAGE_SIZE); DXG_TRACE("unmap fence %d %p", ret, syncobj->mapped_address); syncobj->mapped_address =3D NULL; @@ -994,5 +1010,7 @@ void dxgsyncobject_release(struct kref *refcount) struct dxgsyncobject *syncobj; =20 syncobj =3D container_of(refcount, struct dxgsyncobject, syncobj_kref); + if (syncobj->host_event) + kfree(syncobj->host_event); kfree(syncobj); } diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 1b9410c9152b..8431523f42de 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -101,6 +101,29 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, s= truct hv_device *hdev); void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch); void dxgvmbuschannel_receive(void *ctx); =20 +/* + * The structure describes an event, which will be signaled by + * a message from host. + */ +enum dxghosteventtype { + dxghostevent_cpu_event =3D 1, +}; + +struct dxghostevent { + struct list_head host_event_list_entry; + u64 event_id; + enum dxghosteventtype event_type; +}; + +struct dxghosteventcpu { + struct dxghostevent hdr; + struct dxgprocess *process; + struct eventfd_ctx *cpu_event; + struct completion *completion_event; + bool destroy_after_signal; + bool remove_from_list; +}; + /* * This is GPU synchronization object, which is used to synchronize execut= ion * between GPU contextx/hardware queues or for tracking GPU execution prog= ress. @@ -130,6 +153,8 @@ struct dxgsyncobject { */ struct dxgdevice *device; struct dxgprocess *process; + /* Used by D3DDDI_CPU_NOTIFICATION objects */ + struct dxghosteventcpu *host_event; /* CPU virtual address of the fence value for "device" syncobjects */ void *mapped_address; /* Handle in the process handle table */ @@ -144,6 +169,7 @@ struct dxgsyncobject { u32 stopped:1; /* device syncobject */ u32 monitored_fence:1; + u32 cpu_event:1; u32 shared:1; u32 reserved:27; }; @@ -206,6 +232,11 @@ struct dxgglobal { /* protects the dxgprocess_adapter lists */ struct mutex process_adapter_mutex; =20 + /* list of events, waiting to be signaled by the host */ + struct list_head host_event_list_head; + spinlock_t host_event_list_mutex; + atomic64_t host_event_id; + bool global_channel_initialized; bool async_msg_enabled; bool misc_registered; @@ -228,6 +259,11 @@ struct vmbus_channel *dxgglobal_get_vmbus(void); struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel(void); void dxgglobal_acquire_process_adapter_lock(void); void dxgglobal_release_process_adapter_lock(void); +void dxgglobal_add_host_event(struct dxghostevent *hostevent); +void dxgglobal_remove_host_event(struct dxghostevent *hostevent); +u64 dxgglobal_new_host_event_id(void); +void dxgglobal_signal_host_event(u64 event_id); +struct dxghostevent *dxgglobal_get_host_event(u64 event_id); int dxgglobal_acquire_channel_lock(void); void dxgglobal_release_channel_lock(void); =20 @@ -594,6 +630,31 @@ int dxgvmb_send_create_sync_object(struct dxgprocess *= pr, *args, struct dxgsyncobject *so); int dxgvmb_send_destroy_sync_object(struct dxgprocess *pr, struct d3dkmthandle h); +int dxgvmb_send_signal_sync_object(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dddicb_signalflags flags, + u64 legacy_fence_value, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle *object, + u32 context_count, + struct d3dkmthandle *contexts, + u32 fence_count, u64 *fences, + struct eventfd_ctx *cpu_event, + struct d3dkmthandle device); +int dxgvmb_send_wait_sync_object_gpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle *objects, + u64 *fences, + bool legacy_fence); +int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct + d3dkmt_waitforsynchronizationobjectfromcpu + *args, + u64 cpu_event); int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); @@ -609,6 +670,7 @@ int dxgvmb_send_async_msg(struct dxgvmbuschannel *chann= el, void *command, u32 cmd_size); =20 +void signal_host_cpu_event(struct dxghostevent *eventhdr); int ntstatus2int(struct ntstatus status); =20 #ifdef DEBUG diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 9bc8931c5043..5a5ca8791d27 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -123,6 +123,102 @@ static struct dxgadapter *find_adapter(struct winluid= *luid) return adapter; } =20 +void dxgglobal_add_host_event(struct dxghostevent *event) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + spin_lock_irq(&dxgglobal->host_event_list_mutex); + list_add_tail(&event->host_event_list_entry, + &dxgglobal->host_event_list_head); + spin_unlock_irq(&dxgglobal->host_event_list_mutex); +} + +void dxgglobal_remove_host_event(struct dxghostevent *event) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + spin_lock_irq(&dxgglobal->host_event_list_mutex); + if (event->host_event_list_entry.next !=3D NULL) { + list_del(&event->host_event_list_entry); + event->host_event_list_entry.next =3D NULL; + } + spin_unlock_irq(&dxgglobal->host_event_list_mutex); +} + +void signal_host_cpu_event(struct dxghostevent *eventhdr) +{ + struct dxghosteventcpu *event =3D (struct dxghosteventcpu *)eventhdr; + + if (event->remove_from_list || + event->destroy_after_signal) { + list_del(&eventhdr->host_event_list_entry); + eventhdr->host_event_list_entry.next =3D NULL; + } + if (event->cpu_event) { + DXG_TRACE("signal cpu event"); + eventfd_signal(event->cpu_event, 1); + if (event->destroy_after_signal) + eventfd_ctx_put(event->cpu_event); + } else { + DXG_TRACE("signal completion"); + complete(event->completion_event); + } + if (event->destroy_after_signal) { + DXG_TRACE("destroying event %p", event); + kfree(event); + } +} + +void dxgglobal_signal_host_event(u64 event_id) +{ + struct dxghostevent *event; + unsigned long flags; + struct dxgglobal *dxgglobal =3D dxggbl(); + + DXG_TRACE("Signaling host event %lld", event_id); + + spin_lock_irqsave(&dxgglobal->host_event_list_mutex, flags); + list_for_each_entry(event, &dxgglobal->host_event_list_head, + host_event_list_entry) { + if (event->event_id =3D=3D event_id) { + DXG_TRACE("found event to signal"); + if (event->event_type =3D=3D dxghostevent_cpu_event) + signal_host_cpu_event(event); + else + DXG_ERR("Unknown host event type"); + break; + } + } + spin_unlock_irqrestore(&dxgglobal->host_event_list_mutex, flags); +} + +struct dxghostevent *dxgglobal_get_host_event(u64 event_id) +{ + struct dxghostevent *entry; + struct dxghostevent *event =3D NULL; + struct dxgglobal *dxgglobal =3D dxggbl(); + + spin_lock_irq(&dxgglobal->host_event_list_mutex); + list_for_each_entry(entry, &dxgglobal->host_event_list_head, + host_event_list_entry) { + if (entry->event_id =3D=3D event_id) { + list_del(&entry->host_event_list_entry); + entry->host_event_list_entry.next =3D NULL; + event =3D entry; + break; + } + } + spin_unlock_irq(&dxgglobal->host_event_list_mutex); + return event; +} + +u64 dxgglobal_new_host_event_id(void) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + + return atomic64_inc_return(&dxgglobal->host_event_id); +} + void dxgglobal_acquire_process_adapter_lock(void) { struct dxgglobal *dxgglobal =3D dxggbl(); @@ -720,12 +816,16 @@ static struct dxgglobal *dxgglobal_create(void) INIT_LIST_HEAD(&dxgglobal->vgpu_ch_list_head); INIT_LIST_HEAD(&dxgglobal->adapter_list_head); init_rwsem(&dxgglobal->adapter_list_lock); - init_rwsem(&dxgglobal->channel_lock); =20 + INIT_LIST_HEAD(&dxgglobal->host_event_list_head); + spin_lock_init(&dxgglobal->host_event_list_mutex); + atomic64_set(&dxgglobal->host_event_id, 1); + #ifdef DEBUG dxgk_validate_ioctls(); #endif + return dxgglobal; } =20 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index d323afc85249..6b2dea24a509 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -281,6 +281,22 @@ static void command_vm_to_host_init1(struct dxgkvmb_co= mmand_vm_to_host *command, command->channel_type =3D DXGKVMB_VM_TO_HOST; } =20 +static void signal_guest_event(struct dxgkvmb_command_host_to_vm *packet, + u32 packet_length) +{ + struct dxgkvmb_command_signalguestevent *command =3D (void *)packet; + + if (packet_length < sizeof(struct dxgkvmb_command_signalguestevent)) { + DXG_ERR("invalid signal guest event packet size"); + return; + } + if (command->event =3D=3D 0) { + DXG_ERR("invalid event pointer"); + return; + } + dxgglobal_signal_host_event(command->event); +} + static void process_inband_packet(struct dxgvmbuschannel *channel, struct vmpacket_descriptor *desc) { @@ -297,6 +313,7 @@ static void process_inband_packet(struct dxgvmbuschanne= l *channel, switch (packet->command_type) { case DXGK_VMBCOMMAND_SIGNALGUESTEVENT: case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE: + signal_guest_event(packet, packet_length); break; case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION: break; @@ -959,7 +976,7 @@ dxgvmb_send_create_context(struct dxgadapter *adapter, command->priv_drv_data, args->priv_drv_data_size); if (ret) { - dev_err(DXGDEV, + DXG_ERR( "Faled to copy private data to user"); ret =3D -EINVAL; dxgvmb_send_destroy_context(adapter, process, @@ -1706,6 +1723,206 @@ dxgvmb_send_create_sync_object(struct dxgprocess *p= rocess, return ret; } =20 +int dxgvmb_send_signal_sync_object(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dddicb_signalflags flags, + u64 legacy_fence_value, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle __user *objects, + u32 context_count, + struct d3dkmthandle __user *contexts, + u32 fence_count, + u64 __user *fences, + struct eventfd_ctx *cpu_event_handle, + struct d3dkmthandle device) +{ + int ret; + struct dxgkvmb_command_signalsyncobject *command; + u32 object_size =3D object_count * sizeof(struct d3dkmthandle); + u32 context_size =3D context_count * sizeof(struct d3dkmthandle); + u32 fence_size =3D fences ? fence_count * sizeof(u64) : 0; + u8 *current_pos; + u32 cmd_size =3D sizeof(struct dxgkvmb_command_signalsyncobject) + + object_size + context_size + fence_size; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (context.v) + cmd_size +=3D sizeof(struct d3dkmthandle); + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_SIGNALSYNCOBJECT, + process->host_handle); + + if (flags.enqueue_cpu_event) + command->cpu_event_handle =3D (u64) cpu_event_handle; + else + command->device =3D device; + command->flags =3D flags; + command->fence_value =3D legacy_fence_value; + command->object_count =3D object_count; + command->context_count =3D context_count; + current_pos =3D (u8 *) &command[1]; + ret =3D copy_from_user(current_pos, objects, object_size); + if (ret) { + DXG_ERR("Failed to read objects %p %d", + objects, object_size); + ret =3D -EINVAL; + goto cleanup; + } + current_pos +=3D object_size; + if (context.v) { + command->context_count++; + *(struct d3dkmthandle *) current_pos =3D context; + current_pos +=3D sizeof(struct d3dkmthandle); + } + if (context_size) { + ret =3D copy_from_user(current_pos, contexts, context_size); + if (ret) { + DXG_ERR("Failed to read contexts %p %d", + contexts, context_size); + ret =3D -EINVAL; + goto cleanup; + } + current_pos +=3D context_size; + } + if (fence_size) { + ret =3D copy_from_user(current_pos, fences, fence_size); + if (ret) { + DXG_ERR("Failed to read fences %p %d", + fences, fence_size); + ret =3D -EINVAL; + goto cleanup; + } + } + + if (dxgglobal->async_msg_enabled) { + command->hdr.async_msg =3D 1; + ret =3D dxgvmb_send_async_msg(msg.channel, msg.hdr, msg.size); + } else { + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, + msg.size); + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct + d3dkmt_waitforsynchronizationobjectfromcpu + *args, + u64 cpu_event) +{ + int ret =3D -EINVAL; + struct dxgkvmb_command_waitforsyncobjectfromcpu *command; + u32 object_size =3D args->object_count * sizeof(struct d3dkmthandle); + u32 fence_size =3D args->object_count * sizeof(u64); + u8 *current_pos; + u32 cmd_size =3D sizeof(*command) + object_size + fence_size; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMCPU, + process->host_handle); + command->device =3D args->device; + command->flags =3D args->flags; + command->object_count =3D args->object_count; + command->guest_event_pointer =3D (u64) cpu_event; + current_pos =3D (u8 *) &command[1]; + + ret =3D copy_from_user(current_pos, args->objects, object_size); + if (ret) { + DXG_ERR("failed to copy objects"); + ret =3D -EINVAL; + goto cleanup; + } + current_pos +=3D object_size; + ret =3D copy_from_user(current_pos, args->fence_values, + fence_size); + if (ret) { + DXG_ERR("failed to copy fences"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_wait_sync_object_gpu(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + u32 object_count, + struct d3dkmthandle *objects, + u64 *fences, + bool legacy_fence) +{ + int ret; + struct dxgkvmb_command_waitforsyncobjectfromgpu *command; + u32 fence_size =3D object_count * sizeof(u64); + u32 object_size =3D object_count * sizeof(struct d3dkmthandle); + u8 *current_pos; + u32 cmd_size =3D object_size + fence_size - sizeof(u64) + + sizeof(struct dxgkvmb_command_waitforsyncobjectfromgpu); + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + struct dxgglobal *dxgglobal =3D dxggbl(); + + if (object_count =3D=3D 0 || object_count > D3DDDI_MAX_OBJECT_WAITED_ON) { + ret =3D -EINVAL; + goto cleanup; + } + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_WAITFORSYNCOBJECTFROMGPU, + process->host_handle); + command->context =3D context; + command->object_count =3D object_count; + command->legacy_fence_object =3D legacy_fence; + current_pos =3D (u8 *) command->fence_values; + memcpy(current_pos, fences, fence_size); + current_pos +=3D fence_size; + memcpy(current_pos, objects, object_size); + + if (dxgglobal->async_msg_enabled) { + command->hdr.async_msg =3D 1; + ret =3D dxgvmb_send_async_msg(msg.channel, msg.hdr, msg.size); + } else { + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, + msg.size); + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index bbf5f31cdf81..89fecbcefbc8 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -165,6 +165,13 @@ struct dxgkvmb_command_host_to_vm { enum dxgkvmb_commandtype_host_to_vm command_type; }; =20 +struct dxgkvmb_command_signalguestevent { + struct dxgkvmb_command_host_to_vm hdr; + u64 event; + u64 process_id; + bool dereference_event; +}; + /* Returns ntstatus */ struct dxgkvmb_command_setiospaceregion { struct dxgkvmb_command_vm_to_host hdr; @@ -430,4 +437,45 @@ struct dxgkvmb_command_destroysyncobject { struct d3dkmthandle sync_object; }; =20 +/* The command returns ntstatus */ +struct dxgkvmb_command_signalsyncobject { + struct dxgkvmb_command_vgpu_to_host hdr; + u32 object_count; + struct d3dddicb_signalflags flags; + u32 context_count; + u64 fence_value; + union { + /* Pointer to the guest event object */ + u64 cpu_event_handle; + /* Non zero when signal from CPU is done */ + struct d3dkmthandle device; + }; + /* struct d3dkmthandle ObjectHandleArray[object_count] */ + /* struct d3dkmthandle ContextArray[context_count] */ + /* u64 MonitoredFenceValueArray[object_count] */ +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_waitforsyncobjectfromcpu { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + u32 object_count; + struct d3dddi_waitforsynchronizationobjectfromcpu_flags flags; + u64 guest_event_pointer; + bool dereference_event; + /* struct d3dkmthandle ObjectHandleArray[object_count] */ + /* u64 FenceValueArray [object_count] */ +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_waitforsyncobjectfromgpu { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle context; + /* Must be 1 when bLegacyFenceObject is TRUE */ + u32 object_count; + bool legacy_fence_object; + u64 fence_values[1]; + /* struct d3dkmthandle ObjectHandles[object_count] */ +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 4bba1e209f33..0025e1ee2d4d 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -759,7 +759,7 @@ get_standard_alloc_priv_data(struct dxgdevice *device, res_priv_data =3D vzalloc(res_priv_data_size); if (res_priv_data =3D=3D NULL) { ret =3D -ENOMEM; - dev_err(DXGDEV, + DXG_ERR( "failed to alloc memory for res priv data: %d", res_priv_data_size); goto cleanup; @@ -1065,7 +1065,7 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) alloc_info[i].priv_drv_data, priv_data_size); if (ret) { - dev_err(DXGDEV, + DXG_ERR( "failed to copy priv data"); ret =3D -EFAULT; goto cleanup; @@ -1348,8 +1348,10 @@ dxgkio_create_sync_object(struct dxgprocess *process= , void *__user inargs) struct d3dkmt_createsynchronizationobject2 args; struct dxgdevice *device =3D NULL; struct dxgadapter *adapter =3D NULL; + struct eventfd_ctx *event =3D NULL; struct dxgsyncobject *syncobj =3D NULL; bool device_lock_acquired =3D false; + struct dxghosteventcpu *host_event =3D NULL; =20 ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { @@ -1384,6 +1386,27 @@ dxgkio_create_sync_object(struct dxgprocess *process= , void *__user inargs) goto cleanup; } =20 + if (args.info.type =3D=3D _D3DDDI_CPU_NOTIFICATION) { + event =3D eventfd_ctx_fdget((int) + args.info.cpu_notification.event); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event =3D NULL; + ret =3D -EINVAL; + goto cleanup; + } + host_event =3D syncobj->host_event; + host_event->hdr.event_id =3D dxgglobal_new_host_event_id(); + host_event->cpu_event =3D event; + host_event->remove_from_list =3D false; + host_event->destroy_after_signal =3D false; + host_event->hdr.event_type =3D dxghostevent_cpu_event; + dxgglobal_add_host_event(&host_event->hdr); + args.info.cpu_notification.event =3D host_event->hdr.event_id; + DXG_TRACE("creating CPU notification event: %lld", + args.info.cpu_notification.event); + } + ret =3D dxgvmb_send_create_sync_object(process, adapter, &args, syncobj); if (ret < 0) goto cleanup; @@ -1411,7 +1434,10 @@ dxgkio_create_sync_object(struct dxgprocess *process= , void *__user inargs) if (args.sync_object.v) dxgvmb_send_destroy_sync_object(process, args.sync_object); + event =3D NULL; } + if (event) + eventfd_ctx_put(event); } if (adapter) dxgadapter_release_lock_shared(adapter); @@ -1467,6 +1493,659 @@ dxgkio_destroy_sync_object(struct dxgprocess *proce= ss, void *__user inargs) return ret; } =20 +static int +dxgkio_signal_sync_object(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_signalsynchronizationobject2 args; + struct d3dkmt_signalsynchronizationobject2 *__user in_args =3D inargs; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + int ret; + u32 fence_count =3D 1; + struct eventfd_ctx *event =3D NULL; + struct dxghosteventcpu *host_event =3D NULL; + bool host_event_added =3D false; + u64 host_event_id =3D 0; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.context_count >=3D D3DDDI_MAX_BROADCAST_CONTEXT || + args.object_count > D3DDDI_MAX_OBJECT_SIGNALED) { + ret =3D -EINVAL; + goto cleanup; + } + + if (args.flags.enqueue_cpu_event) { + host_event =3D kzalloc(sizeof(*host_event), GFP_KERNEL); + if (host_event =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + host_event->process =3D process; + event =3D eventfd_ctx_fdget((int)args.cpu_event_handle); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event =3D NULL; + ret =3D -EINVAL; + goto cleanup; + } + fence_count =3D 0; + host_event->cpu_event =3D event; + host_event_id =3D dxgglobal_new_host_event_id(); + host_event->hdr.event_type =3D dxghostevent_cpu_event; + host_event->hdr.event_id =3D host_event_id; + host_event->remove_from_list =3D true; + host_event->destroy_after_signal =3D true; + dxgglobal_add_host_event(&host_event->hdr); + host_event_added =3D true; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_signal_sync_object(process, adapter, + args.flags, args.fence.fence_value, + args.context, args.object_count, + in_args->object_array, + args.context_count, + in_args->contexts, fence_count, + NULL, (void *)host_event_id, + zerohandle); + + /* + * When the send operation succeeds, the host event will be destroyed + * after signal from the host + */ + +cleanup: + + if (ret < 0) { + if (host_event_added) { + /* The event might be signaled and destroyed by host */ + host_event =3D (struct dxghosteventcpu *) + dxgglobal_get_host_event(host_event_id); + if (host_event) { + eventfd_ctx_put(event); + event =3D NULL; + kfree(host_event); + host_event =3D NULL; + } + } + if (event) + eventfd_ctx_put(event); + if (host_event) + kfree(host_event); + } + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_signal_sync_object_cpu(struct dxgprocess *process, void *__user ina= rgs) +{ + struct d3dkmt_signalsynchronizationobjectfromcpu args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + if (args.object_count =3D=3D 0 || + args.object_count > D3DDDI_MAX_OBJECT_SIGNALED) { + DXG_TRACE("Too many syncobjects : %d", args.object_count); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_signal_sync_object(process, adapter, + args.flags, 0, zerohandle, + args.object_count, args.objects, 0, + NULL, args.object_count, + args.fence_values, NULL, + args.device); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_signal_sync_object_gpu(struct dxgprocess *process, void *__user ina= rgs) +{ + struct d3dkmt_signalsynchronizationobjectfromgpu args; + struct d3dkmt_signalsynchronizationobjectfromgpu *__user user_args =3D + inargs; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dddicb_signalflags flags =3D { }; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.object_count =3D=3D 0 || + args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_signal_sync_object(process, adapter, + flags, 0, zerohandle, + args.object_count, + args.objects, 1, + &user_args->context, + args.object_count, + args.monitored_fence_values, NULL, + zerohandle); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_signal_sync_object_gpu2(struct dxgprocess *process, void *__user in= args) +{ + struct d3dkmt_signalsynchronizationobjectfromgpu2 args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dkmthandle context_handle; + struct eventfd_ctx *event =3D NULL; + u64 *fences =3D NULL; + u32 fence_count =3D 0; + int ret; + struct dxghosteventcpu *host_event =3D NULL; + bool host_event_added =3D false; + u64 host_event_id =3D 0; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.flags.enqueue_cpu_event) { + if (args.object_count !=3D 0 || args.cpu_event_handle =3D=3D 0) { + DXG_ERR("Bad input in EnqueueCpuEvent: %d %lld", + args.object_count, args.cpu_event_handle); + ret =3D -EINVAL; + goto cleanup; + } + } else if (args.object_count =3D=3D 0 || + args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE || + args.context_count =3D=3D 0 || + args.context_count > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("Invalid input: %d %d", + args.object_count, args.context_count); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D copy_from_user(&context_handle, args.contexts, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy context handle"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.flags.enqueue_cpu_event) { + host_event =3D kzalloc(sizeof(*host_event), GFP_KERNEL); + if (host_event =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + host_event->process =3D process; + event =3D eventfd_ctx_fdget((int)args.cpu_event_handle); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event =3D NULL; + ret =3D -EINVAL; + goto cleanup; + } + fence_count =3D 0; + host_event->cpu_event =3D event; + host_event_id =3D dxgglobal_new_host_event_id(); + host_event->hdr.event_id =3D host_event_id; + host_event->hdr.event_type =3D dxghostevent_cpu_event; + host_event->remove_from_list =3D true; + host_event->destroy_after_signal =3D true; + dxgglobal_add_host_event(&host_event->hdr); + host_event_added =3D true; + } else { + fences =3D args.monitored_fence_values; + fence_count =3D args.object_count; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + context_handle); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_signal_sync_object(process, adapter, + args.flags, 0, zerohandle, + args.object_count, args.objects, + args.context_count, args.contexts, + fence_count, fences, + (void *)host_event_id, zerohandle); + +cleanup: + + if (ret < 0) { + if (host_event_added) { + /* The event might be signaled and destroyed by host */ + host_event =3D (struct dxghosteventcpu *) + dxgglobal_get_host_event(host_event_id); + if (host_event) { + eventfd_ctx_put(event); + event =3D NULL; + kfree(host_event); + host_event =3D NULL; + } + } + if (event) + eventfd_ctx_put(event); + if (host_event) + kfree(host_event); + } + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_wait_sync_object(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_waitforsynchronizationobject2 args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.object_count > D3DDDI_MAX_OBJECT_WAITED_ON || + args.object_count =3D=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + DXG_TRACE("Fence value: %lld", args.fence.fence_value); + ret =3D dxgvmb_send_wait_sync_object_gpu(process, adapter, + args.context, args.object_count, + args.object_array, + &args.fence.fence_value, true); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_wait_sync_object_cpu(struct dxgprocess *process, void *__user inarg= s) +{ + struct d3dkmt_waitforsynchronizationobjectfromcpu args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct eventfd_ctx *event =3D NULL; + struct dxghosteventcpu host_event =3D { }; + struct dxghosteventcpu *async_host_event =3D NULL; + struct completion local_event =3D { }; + u64 event_id =3D 0; + int ret; + bool host_event_added =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE || + args.object_count =3D=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + + if (args.async_event) { + async_host_event =3D kzalloc(sizeof(*async_host_event), + GFP_KERNEL); + if (async_host_event =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + async_host_event->process =3D process; + event =3D eventfd_ctx_fdget((int)args.async_event); + if (IS_ERR(event)) { + DXG_ERR("failed to reference the event"); + event =3D NULL; + ret =3D -EINVAL; + goto cleanup; + } + async_host_event->cpu_event =3D event; + async_host_event->hdr.event_id =3D dxgglobal_new_host_event_id(); + async_host_event->destroy_after_signal =3D true; + async_host_event->hdr.event_type =3D dxghostevent_cpu_event; + dxgglobal_add_host_event(&async_host_event->hdr); + event_id =3D async_host_event->hdr.event_id; + host_event_added =3D true; + } else { + init_completion(&local_event); + host_event.completion_event =3D &local_event; + host_event.hdr.event_id =3D dxgglobal_new_host_event_id(); + host_event.hdr.event_type =3D dxghostevent_cpu_event; + dxgglobal_add_host_event(&host_event.hdr); + event_id =3D host_event.hdr.event_id; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_wait_sync_object_cpu(process, adapter, + &args, event_id); + if (ret < 0) + goto cleanup; + + if (args.async_event =3D=3D 0) { + dxgadapter_release_lock_shared(adapter); + adapter =3D NULL; + ret =3D wait_for_completion_interruptible(&local_event); + if (ret) { + DXG_ERR("wait_completion_interruptible: %d", + ret); + ret =3D -ERESTARTSYS; + } + } + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + if (host_event.hdr.event_id) + dxgglobal_remove_host_event(&host_event.hdr); + if (ret < 0) { + if (host_event_added) { + async_host_event =3D (struct dxghosteventcpu *) + dxgglobal_get_host_event(event_id); + if (async_host_event) { + if (async_host_event->hdr.event_type =3D=3D + dxghostevent_cpu_event) { + eventfd_ctx_put(event); + event =3D NULL; + kfree(async_host_event); + async_host_event =3D NULL; + } else { + DXG_ERR("Invalid event type"); + DXGKRNL_ASSERT(0); + } + } + } + if (event) + eventfd_ctx_put(event); + if (async_host_event) + kfree(async_host_event); + } + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_wait_sync_object_gpu(struct dxgprocess *process, void *__user inarg= s) +{ + struct d3dkmt_waitforsynchronizationobjectfromgpu args; + struct dxgcontext *context =3D NULL; + struct d3dkmthandle device_handle =3D {}; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct dxgsyncobject *syncobj =3D NULL; + struct d3dkmthandle *objects =3D NULL; + u32 object_size; + u64 *fences =3D NULL; + int ret; + enum hmgrentry_type syncobj_type =3D HMGRENTRY_TYPE_FREE; + bool monitored_fence =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.object_count > DXG_MAX_VM_BUS_PACKET_SIZE || + args.object_count =3D=3D 0) { + DXG_ERR("Invalid object count: %d", args.object_count); + ret =3D -EINVAL; + goto cleanup; + } + + object_size =3D sizeof(struct d3dkmthandle) * args.object_count; + objects =3D vzalloc(object_size); + if (objects =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user(objects, args.objects, object_size); + if (ret) { + DXG_ERR("failed to copy objects"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); + context =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (context) { + device_handle =3D context->device_handle; + syncobj_type =3D + hmgrtable_get_object_type(&process->handle_table, + objects[0]); + } + if (device_handle.v =3D=3D 0) { + DXG_ERR("Invalid context handle: %x", args.context.v); + ret =3D -EINVAL; + } else { + if (syncobj_type =3D=3D HMGRENTRY_TYPE_MONITOREDFENCE) { + monitored_fence =3D true; + } else if (syncobj_type =3D=3D HMGRENTRY_TYPE_DXGSYNCOBJECT) { + syncobj =3D + hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + objects[0]); + if (syncobj =3D=3D NULL) { + DXG_ERR("Invalid syncobj: %x", + objects[0].v); + ret =3D -EINVAL; + } else { + monitored_fence =3D syncobj->monitored_fence; + } + } else { + DXG_ERR("Invalid syncobj type: %x", + objects[0].v); + ret =3D -EINVAL; + } + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED); + + if (ret < 0) + goto cleanup; + + if (monitored_fence) { + object_size =3D sizeof(u64) * args.object_count; + fences =3D vzalloc(object_size); + if (fences =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user(fences, args.monitored_fence_values, + object_size); + if (ret) { + DXG_ERR("failed to copy fences"); + ret =3D -EINVAL; + goto cleanup; + } + } else { + fences =3D &args.fence_value; + } + + device =3D dxgprocess_device_by_handle(process, device_handle); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_wait_sync_object_gpu(process, adapter, + args.context, args.object_count, + objects, fences, + !monitored_fence); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + if (objects) + vfree(objects); + if (fences && fences !=3D &args.fence_value) + vfree(fences); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static struct ioctl_desc ioctls[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -1485,8 +2164,8 @@ static struct ioctl_desc ioctls[] =3D { /* 0x0e */ {}, /* 0x0f */ {}, /* 0x10 */ {dxgkio_create_sync_object, LX_DXCREATESYNCHRONIZATIONOBJECT}, -/* 0x11 */ {}, -/* 0x12 */ {}, +/* 0x11 */ {dxgkio_signal_sync_object, LX_DXSIGNALSYNCHRONIZATIONOBJECT}, +/* 0x12 */ {dxgkio_wait_sync_object, LX_DXWAITFORSYNCHRONIZATIONOBJECT}, /* 0x13 */ {dxgkio_destroy_allocation, LX_DXDESTROYALLOCATION2}, /* 0x14 */ {dxgkio_enum_adapters, LX_DXENUMADAPTERS2}, /* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER}, @@ -1517,17 +2196,22 @@ static struct ioctl_desc ioctls[] =3D { /* 0x2e */ {}, /* 0x2f */ {}, /* 0x30 */ {}, -/* 0x31 */ {}, -/* 0x32 */ {}, -/* 0x33 */ {}, +/* 0x31 */ {dxgkio_signal_sync_object_cpu, + LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU}, +/* 0x32 */ {dxgkio_signal_sync_object_gpu, + LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU}, +/* 0x33 */ {dxgkio_signal_sync_object_gpu2, + LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2}, /* 0x34 */ {}, /* 0x35 */ {}, /* 0x36 */ {}, /* 0x37 */ {}, /* 0x38 */ {}, /* 0x39 */ {}, -/* 0x3a */ {}, -/* 0x3b */ {}, +/* 0x3a */ {dxgkio_wait_sync_object_cpu, + LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU}, +/* 0x3b */ {dxgkio_wait_sync_object_gpu, + LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU}, /* 0x3c */ {}, /* 0x3d */ {}, /* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3}, diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h index a51b29a6a68f..ee2ebfdd1c13 100644 --- a/drivers/hv/dxgkrnl/misc.h +++ b/drivers/hv/dxgkrnl/misc.h @@ -25,6 +25,8 @@ extern const struct d3dkmthandle zerohandle; * The locks here are in the order from lowest to highest. * When a lower lock is held, the higher lock should not be acquired. * + * device_list_mutex + * host_event_list_mutex * channel_lock (VMBus channel lock) * fd_mutex * plistmutex (process list mutex) diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 4e1069f41d76..39055b0c1069 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -60,6 +60,9 @@ struct winluid { =20 #define D3DKMT_CREATEALLOCATION_MAX 1024 #define D3DKMT_ADAPTERS_MAX 64 +#define D3DDDI_MAX_BROADCAST_CONTEXT 64 +#define D3DDDI_MAX_OBJECT_WAITED_ON 32 +#define D3DDDI_MAX_OBJECT_SIGNALED 32 =20 struct d3dkmt_adapterinfo { struct d3dkmthandle adapter_handle; @@ -343,6 +346,148 @@ struct d3dkmt_createsynchronizationobject2 { __u32 reserved1; }; =20 +struct d3dkmt_waitforsynchronizationobject2 { + struct d3dkmthandle context; + __u32 object_count; + struct d3dkmthandle object_array[D3DDDI_MAX_OBJECT_WAITED_ON]; + union { + struct { + __u64 fence_value; + } fence; + __u64 reserved[8]; + }; +}; + +struct d3dddicb_signalflags { + union { + struct { + __u32 signal_at_submission:1; + __u32 enqueue_cpu_event:1; + __u32 allow_fence_rewind:1; + __u32 reserved:28; + __u32 DXGK_SIGNAL_FLAG_INTERNAL0:1; + }; + __u32 value; + }; +}; + +struct d3dkmt_signalsynchronizationobject2 { + struct d3dkmthandle context; + __u32 object_count; + struct d3dkmthandle object_array[D3DDDI_MAX_OBJECT_SIGNALED]; + struct d3dddicb_signalflags flags; + __u32 context_count; + struct d3dkmthandle contexts[D3DDDI_MAX_BROADCAST_CONTEXT]; + union { + struct { + __u64 fence_value; + } fence; + __u64 cpu_event_handle; + __u64 reserved[8]; + }; +}; + +struct d3dddi_waitforsynchronizationobjectfromcpu_flags { + union { + struct { + __u32 wait_any:1; + __u32 reserved:31; + }; + __u32 value; + }; +}; + +struct d3dkmt_waitforsynchronizationobjectfromcpu { + struct d3dkmthandle device; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; + __u64 *fence_values; +#else + __u64 objects; + __u64 fence_values; +#endif + __u64 async_event; + struct d3dddi_waitforsynchronizationobjectfromcpu_flags flags; +}; + +struct d3dkmt_signalsynchronizationobjectfromcpu { + struct d3dkmthandle device; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; + __u64 *fence_values; +#else + __u64 objects; + __u64 fence_values; +#endif + struct d3dddicb_signalflags flags; +}; + +struct d3dkmt_waitforsynchronizationobjectfromgpu { + struct d3dkmthandle context; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; +#else + __u64 objects; +#endif + union { +#ifdef __KERNEL__ + __u64 *monitored_fence_values; +#else + __u64 monitored_fence_values; +#endif + __u64 fence_value; + __u64 reserved[8]; + }; +}; + +struct d3dkmt_signalsynchronizationobjectfromgpu { + struct d3dkmthandle context; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; +#else + __u64 objects; +#endif + union { +#ifdef __KERNEL__ + __u64 *monitored_fence_values; +#else + __u64 monitored_fence_values; +#endif + __u64 reserved[8]; + }; +}; + +struct d3dkmt_signalsynchronizationobjectfromgpu2 { + __u32 object_count; + __u32 reserved1; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; +#else + __u64 objects; +#endif + struct d3dddicb_signalflags flags; + __u32 context_count; +#ifdef __KERNEL__ + struct d3dkmthandle *contexts; +#else + __u64 contexts; +#endif + union { + __u64 fence_value; + __u64 cpu_event_handle; +#ifdef __KERNEL__ + __u64 *monitored_fence_values; +#else + __u64 monitored_fence_values; +#endif + __u64 reserved[8]; + }; +}; + struct d3dkmt_destroysynchronizationobject { struct d3dkmthandle sync_object; }; @@ -576,6 +721,10 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) #define LX_DXCREATESYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x10, struct d3dkmt_createsynchronizationobject2) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECT \ + _IOWR(0x47, 0x11, struct d3dkmt_signalsynchronizationobject2) +#define LX_DXWAITFORSYNCHRONIZATIONOBJECT \ + _IOWR(0x47, 0x12, struct d3dkmt_waitforsynchronizationobject2) #define LX_DXDESTROYALLOCATION2 \ _IOWR(0x47, 0x13, struct d3dkmt_destroyallocation2) #define LX_DXENUMADAPTERS2 \ @@ -586,6 +735,16 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) #define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ + _IOWR(0x47, 0x31, struct d3dkmt_signalsynchronizationobjectfromcpu) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU \ + _IOWR(0x47, 0x32, struct d3dkmt_signalsynchronizationobjectfromgpu) +#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2 \ + _IOWR(0x47, 0x33, struct d3dkmt_signalsynchronizationobjectfromgpu2) +#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU \ + _IOWR(0x47, 0x3a, struct d3dkmt_waitforsynchronizationobjectfromcpu) +#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU \ + _IOWR(0x47, 0x3b, struct d3dkmt_waitforsynchronizationobjectfromgpu) #define LX_DXENUMADAPTERS3 \ _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 542483F99C0 for ; Thu, 19 Mar 2026 20:25:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951935; cv=none; b=NS7zfPeaA/g71lCPIL019K5QRByJqYQOjml6BsDjzpQWn40p88zPMVYYgFi1BOVORH72dpIQ7Ts26x15vZyPlhBOGxyqdveIw/jOnpJ8va1ssPAB4xrrs2Se0CS5zdXN1nxczltft3pePVbyJT+VOWbTkEiJ1zsuuMQf21AmceI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951935; c=relaxed/simple; bh=OcC5mzzGJ4jyW3tE/pecqqNwYt2+LrsdDdXg/j4BCaU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iVW+6SzCHUhk6waWjF9ywlx5SmaQw/BOKzxUVifZ/LXIH+DJJSJgt1KPvxgPv+HkpeoUHnVUcMwEhi9MGt0GSI8IRkB7cRTLA3AV+B4Qwl7ArNd+xnbRkGF12DM0wBuhfpexTm+Bab+3k0puw6KK1sqV6IKYpPjwRuoNLNJc3T8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=meEt66Gr; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="meEt66Gr" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-48628ce9ab5so17565025e9.2 for ; Thu, 19 Mar 2026 13:25:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951926; x=1774556726; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=oAZE4/6c4RcyDRxzDQdEx/qHk8QrzPDuRZgVPNWiHNg=; b=meEt66Gr6HuxmN0SLCazPjZOkeCoVMAecRyHsddhgKN8oVUrSuOOG+rjYU3808GUYo t/g5pnLg9Dw2AWZRT1eqQrp/fywtyI3o4k4A3LpR9pbhuGVTpEjLF5YOqsktqsSgWYYr GZwEN20a1gPM+IBNLP37ugMCeH0kXG+joJT7A8aswbIE6x+a/4gT2Q0Y6egs8GWn2g4a /c+kdV0ECc4fe+sCE1Mw0dgV8eTQoP7qXHJLKTvl842H40hZ+HXuHcGKAP6ut2WeWm0R KBdFWYgscj7v+/sXeveDJpPMU0OghgaFIh4o1Xf8pxBlBmFcJs0GZKGy6cZyd8ifpsgI C4rQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951926; x=1774556726; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=oAZE4/6c4RcyDRxzDQdEx/qHk8QrzPDuRZgVPNWiHNg=; b=H1I0hpmeR6DnT4eWV2xk7nnpWGpT/o6QJI0Xmo3N07kbCZFfgY8BAL+m4FUr/1CSJJ XO7MEDT0s36HMRUAXxMQqCaEiIFL+AsuVhzDadTdVJC0I11EWwM/lOCxaA9P1bkphi8H FcVR3A8dINvyIhua40Wxwn0J5ASS6/TEo6yx1g9Koc0GaFOeSD9niEKDXTTXcN52hmqD UXxlTGq0Oc8rFwfnPjK2kxsKcyS2421R8+U66vD8XluPzbDipFKWHgayhSdSrN681WVY xaHuPg+Ac4dbrBOJDckzmUGS0HW9+fu9KFQy6x+hELfwng1TeqR8l+85cI29GetJQ/oi pF0g== X-Gm-Message-State: AOJu0Yz2IqKuCj1OXBIHeXE3t/Wco08IZ6kG6P90xPkAPSll0PRbs1TF G7Z9g05DUKayNEFbIG9YVgY+TjIplEN3MaZwkuU4mc9IhOx9KpAKy6YSXdzWoZWkzbs= X-Gm-Gg: ATEYQzwas3wtwNl33EtFirEaRglxTrZ+HXWB8yRORt2uxy5fZE/CbyHtpwWm7Q7pTbP sVRc3Jlc/g24g8WHzU8pXi3PnTdwHFgbtJWnEefM6SJmShpMUczEwxTgTU8+hDM9R0IvjjiuGhm FaS6uRrKsDVVZ8s9mhdncyBjIGsgZ9sTrGmu1jnd4i4rZvSKJ97TsJLp0efm3zCMvSz+u5HXBeg xaw2P0P073fdaZb647guJIk+cFqxWmbb2OOi0zmIRfCrCU58cOqRdnDHforD6Be9/Os1f/wa1QX FHgJvYWiShbKN34gqv9ZnLQHXy7qAJCCVtt56obwg+YIlgwV+S5eO+fCTMq2EOgnn/gAi07ue9g dGXCMuHNf69K7YrNgGGL7AGciszTF6Y/m6MyGOojil1Jtez3gizYasu+/LKeUZjQF1Kf1YTcy46 Xm580GMCru9wL10Vun8E01+Dazg+CJyZH5rkezvy0SZ0guyGM1 X-Received: by 2002:a05:600c:c083:b0:485:3f72:324d with SMTP id 5b1f17b1804b1-486fee0481amr5002735e9.14.1773951926227; Thu, 19 Mar 2026 13:25:26 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.24 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:25 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 11/55] drivers: hv: dxgkrnl: Sharing of dxgresource objects Date: Thu, 19 Mar 2026 20:24:25 +0000 Message-ID: <20260319202509.63802-12-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement creation of shared resources and ioctls for sharing dxgresource objects between processes in the virtual machine. A dxgresource object is a collection of dxgallocation objects. The driver API allows addition/removal of allocations to a resource, but has limitations on addition/removal of allocations to a shared resource. When a resource is "sealed", addition/removal of allocations is not allowed. Resources are shared using file descriptor (FD) handles. The name "NT handle" is used to be compatible with Windows implementation. An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The given FD handle could be sent to another process using any Linux API. To use a shared resource object in other ioctls the object needs to be opened using its FD handle. An resource object is opened by the LX_DXOPENRESOURCEFROMNTHANDLE ioctl. This ioctl returns a d3dkmthandle value, which can be used to reference the resource object. The LX_DXQUERYRESOURCEINFOFROMNTHANDLE ioctl is used to query private driver data of a shared resource object. This private data needs to be used to actually open the object using the LX_DXOPENRESOURCEFROMNTHANDLE ioctl. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 81 ++++ drivers/hv/dxgkrnl/dxgkrnl.h | 77 ++++ drivers/hv/dxgkrnl/dxgmodule.c | 1 + drivers/hv/dxgkrnl/dxgvmbus.c | 127 +++++ drivers/hv/dxgkrnl/dxgvmbus.h | 30 ++ drivers/hv/dxgkrnl/ioctl.c | 792 +++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 96 ++++ 7 files changed, 1200 insertions(+), 4 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index 04d827a15c54..26fce9aba4f3 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -160,6 +160,17 @@ void dxgadapter_remove_process(struct dxgprocess_adapt= er *process_info) list_del(&process_info->adapter_process_list_entry); } =20 +void dxgadapter_remove_shared_resource(struct dxgadapter *adapter, + struct dxgsharedresource *object) +{ + down_write(&adapter->shared_resource_list_lock); + if (object->shared_resource_list_entry.next) { + list_del(&object->shared_resource_list_entry); + object->shared_resource_list_entry.next =3D NULL; + } + up_write(&adapter->shared_resource_list_lock); +} + void dxgadapter_add_syncobj(struct dxgadapter *adapter, struct dxgsyncobject *object) { @@ -489,6 +500,69 @@ void dxgdevice_remove_resource(struct dxgdevice *devic= e, } } =20 +struct dxgsharedresource *dxgsharedresource_create(struct dxgadapter *adap= ter) +{ + struct dxgsharedresource *resource; + + resource =3D kzalloc(sizeof(*resource), GFP_KERNEL); + if (resource) { + INIT_LIST_HEAD(&resource->resource_list_head); + kref_init(&resource->sresource_kref); + mutex_init(&resource->fd_mutex); + resource->adapter =3D adapter; + } + return resource; +} + +void dxgsharedresource_destroy(struct kref *refcount) +{ + struct dxgsharedresource *resource; + + resource =3D container_of(refcount, struct dxgsharedresource, + sresource_kref); + if (resource->runtime_private_data) + vfree(resource->runtime_private_data); + if (resource->resource_private_data) + vfree(resource->resource_private_data); + if (resource->alloc_private_data_sizes) + vfree(resource->alloc_private_data_sizes); + if (resource->alloc_private_data) + vfree(resource->alloc_private_data); + kfree(resource); +} + +void dxgsharedresource_add_resource(struct dxgsharedresource *shared_resou= rce, + struct dxgresource *resource) +{ + down_write(&shared_resource->adapter->shared_resource_list_lock); + DXG_TRACE("Adding resource: %p %p", shared_resource, resource); + list_add_tail(&resource->shared_resource_list_entry, + &shared_resource->resource_list_head); + kref_get(&shared_resource->sresource_kref); + kref_get(&resource->resource_kref); + resource->shared_owner =3D shared_resource; + up_write(&shared_resource->adapter->shared_resource_list_lock); +} + +void dxgsharedresource_remove_resource(struct dxgsharedresource + *shared_resource, + struct dxgresource *resource) +{ + struct dxgadapter *adapter =3D shared_resource->adapter; + + down_write(&adapter->shared_resource_list_lock); + DXG_TRACE("Removing resource: %p %p", shared_resource, resource); + if (resource->shared_resource_list_entry.next) { + list_del(&resource->shared_resource_list_entry); + resource->shared_resource_list_entry.next =3D NULL; + kref_put(&shared_resource->sresource_kref, + dxgsharedresource_destroy); + resource->shared_owner =3D NULL; + kref_put(&resource->resource_kref, dxgresource_release); + } + up_write(&adapter->shared_resource_list_lock); +} + struct dxgresource *dxgresource_create(struct dxgdevice *device) { struct dxgresource *resource; @@ -532,6 +606,7 @@ void dxgresource_destroy(struct dxgresource *resource) struct d3dkmt_destroyallocation2 args =3D { }; int destroyed =3D test_and_set_bit(0, &resource->flags); struct dxgdevice *device =3D resource->device; + struct dxgsharedresource *shared_resource; =20 if (!destroyed) { dxgresource_free_handle(resource); @@ -547,6 +622,12 @@ void dxgresource_destroy(struct dxgresource *resource) dxgallocation_destroy(alloc); } dxgdevice_remove_resource(device, resource); + shared_resource =3D resource->shared_owner; + if (shared_resource) { + dxgsharedresource_remove_resource(shared_resource, + resource); + resource->shared_owner =3D NULL; + } } kref_put(&resource->resource_kref, dxgresource_release); } diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 8431523f42de..0336e1843223 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -38,6 +38,7 @@ struct dxgdevice; struct dxgcontext; struct dxgallocation; struct dxgresource; +struct dxgsharedresource; struct dxgsyncobject; =20 /* @@ -372,6 +373,8 @@ struct dxgadapter { struct list_head adapter_list_entry; /* The list of dxgprocess_adapter entries */ struct list_head adapter_process_list_head; + /* List of all dxgsharedresource objects */ + struct list_head shared_resource_list_head; /* List of all non-device dxgsyncobject objects */ struct list_head syncobj_list_head; /* This lock protects shared resource and syncobject lists */ @@ -405,6 +408,8 @@ void dxgadapter_remove_syncobj(struct dxgsyncobject *so= ); void dxgadapter_add_process(struct dxgadapter *adapter, struct dxgprocess_adapter *process_info); void dxgadapter_remove_process(struct dxgprocess_adapter *process_info); +void dxgadapter_remove_shared_resource(struct dxgadapter *adapter, + struct dxgsharedresource *object); =20 /* * The object represent the device object. @@ -484,6 +489,64 @@ void dxgcontext_destroy_safe(struct dxgprocess *pr, st= ruct dxgcontext *ctx); void dxgcontext_release(struct kref *refcount); bool dxgcontext_is_active(struct dxgcontext *ctx); =20 +/* + * A shared resource object is created to track the list of dxgresource ob= jects, + * which are opened for the same underlying shared resource. + * Objects are shared by using a file descriptor handle. + * FD is created by calling dxgk_share_objects and providing shandle to + * dxgsharedresource. The FD points to a dxgresource object, which is crea= ted + * by calling dxgk_open_resource_nt. dxgresource object is referenced by = the + * FD. + * + * The object is referenced by every dxgresource in its list. + * + */ +struct dxgsharedresource { + /* Every dxgresource object in the resource list takes a reference */ + struct kref sresource_kref; + struct dxgadapter *adapter; + /* List of dxgresource objects, opened for the shared resource. */ + /* Protected by dxgadapter::shared_resource_list_lock */ + struct list_head resource_list_head; + /* Entry in the list of dxgsharedresource in dxgadapter */ + /* Protected by dxgadapter::shared_resource_list_lock */ + struct list_head shared_resource_list_entry; + struct mutex fd_mutex; + /* Referenced by file descriptors */ + int host_shared_handle_nt_reference; + /* Corresponding global handle in the host */ + struct d3dkmthandle host_shared_handle; + /* + * When the sync object is shared by NT handle, this is the + * corresponding handle in the host + */ + struct d3dkmthandle host_shared_handle_nt; + /* Values below are computed when the resource is sealed */ + u32 runtime_private_data_size; + u32 alloc_private_data_size; + u32 resource_private_data_size; + u32 allocation_count; + union { + struct { + /* Cannot add new allocations */ + u32 sealed:1; + u32 reserved:31; + }; + long flags; + }; + u32 *alloc_private_data_sizes; + u8 *alloc_private_data; + u8 *runtime_private_data; + u8 *resource_private_data; +}; + +struct dxgsharedresource *dxgsharedresource_create(struct dxgadapter *adap= ter); +void dxgsharedresource_destroy(struct kref *refcount); +void dxgsharedresource_add_resource(struct dxgsharedresource *sres, + struct dxgresource *res); +void dxgsharedresource_remove_resource(struct dxgsharedresource *sres, + struct dxgresource *res); + struct dxgresource { struct kref resource_kref; enum dxgobjectstate object_state; @@ -504,6 +567,8 @@ struct dxgresource { }; long flags; }; + /* Owner of the shared resource */ + struct dxgsharedresource *shared_owner; }; =20 struct dxgresource *dxgresource_create(struct dxgdevice *dev); @@ -658,6 +723,18 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess= *process, int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); +int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process, + struct d3dkmthandle object, + struct d3dkmthandle *shared_handle); +int dxgvmb_send_destroy_nt_shared_object(struct d3dkmthandle shared_handle= ); +int dxgvmb_send_open_resource(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle device, + struct d3dkmthandle global_share, + u32 allocation_count, + u32 total_priv_drv_data_size, + struct d3dkmthandle *resource_handle, + struct d3dkmthandle *alloc_handles); int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device, enum d3dkmdt_standardallocationtype t, struct d3dkmdt_gdisurfacedata *data, diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 5a5ca8791d27..69e221613af9 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -258,6 +258,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_= t *guid, init_rwsem(&adapter->core_lock); =20 INIT_LIST_HEAD(&adapter->adapter_process_list_head); + INIT_LIST_HEAD(&adapter->shared_resource_list_head); INIT_LIST_HEAD(&adapter->syncobj_list_head); init_rwsem(&adapter->shared_resource_list_lock); adapter->pci_dev =3D dev; diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 6b2dea24a509..b3a4377c8b0b 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -712,6 +712,79 @@ int dxgvmb_send_destroy_process(struct d3dkmthandle pr= ocess) return ret; } =20 +int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process, + struct d3dkmthandle object, + struct d3dkmthandle *shared_handle) +{ + struct dxgkvmb_command_createntsharedobject *command; + int ret; + struct dxgvmbusmsg msg; + + ret =3D init_message(&msg, NULL, process, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + command_vm_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_CREATENTSHAREDOBJECT, + process->host_handle); + command->object =3D object; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + ret =3D dxgvmb_send_sync_msg(dxgglobal_get_dxgvmbuschannel(), + msg.hdr, msg.size, shared_handle, + sizeof(*shared_handle)); + + dxgglobal_release_channel_lock(); + + if (ret < 0) + goto cleanup; + if (shared_handle->v =3D=3D 0) { + DXG_ERR("failed to create NT shared object"); + ret =3D -ENOTRECOVERABLE; + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_destroy_nt_shared_object(struct d3dkmthandle shared_handle) +{ + struct dxgkvmb_command_destroyntsharedobject *command; + int ret; + struct dxgvmbusmsg msg; + + ret =3D init_message(&msg, NULL, NULL, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + command_vm_to_host_init1(&command->hdr, + DXGK_VMBCOMMAND_DESTROYNTSHAREDOBJECT); + command->shared_handle =3D shared_handle; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + ret =3D dxgvmb_send_sync_msg_ntstatus(dxgglobal_get_dxgvmbuschannel(), + msg.hdr, msg.size); + + dxgglobal_release_channel_lock(); + +cleanup: + free_message(&msg, NULL); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_destroy_sync_object(struct dxgprocess *process, struct d3dkmthandle sync_object) { @@ -1552,6 +1625,60 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess= *process, return ret; } =20 +int dxgvmb_send_open_resource(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle device, + struct d3dkmthandle global_share, + u32 allocation_count, + u32 total_priv_drv_data_size, + struct d3dkmthandle *resource_handle, + struct d3dkmthandle *alloc_handles) +{ + struct dxgkvmb_command_openresource *command; + struct dxgkvmb_command_openresource_return *result; + struct d3dkmthandle *handles; + int ret; + int i; + u32 result_size =3D allocation_count * sizeof(struct d3dkmthandle) + + sizeof(*result); + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; + + ret =3D init_message_res(&msg, adapter, process, sizeof(*command), + result_size); + if (ret) + goto cleanup; + command =3D msg.msg; + result =3D msg.res; + + command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_OPENRESOURCE, + process->host_handle); + command->device =3D device; + command->nt_security_sharing =3D 1; + command->global_share =3D global_share; + command->allocation_count =3D allocation_count; + command->total_priv_drv_data_size =3D total_priv_drv_data_size; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + result, msg.res_size); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result->status); + if (ret < 0) + goto cleanup; + + *resource_handle =3D result->resource; + handles =3D (struct d3dkmthandle *) &result[1]; + for (i =3D 0; i < allocation_count; i++) + alloc_handles[i] =3D handles[i]; + +cleanup: + free_message((struct dxgvmbusmsg *)&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device, enum d3dkmdt_standardallocationtype alloctype, struct d3dkmdt_gdisurfacedata *alloc_data, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 89fecbcefbc8..73d7adac60a1 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -172,6 +172,21 @@ struct dxgkvmb_command_signalguestevent { bool dereference_event; }; =20 +/* + * The command returns struct d3dkmthandle of a shared object for the + * given pre-process object + */ +struct dxgkvmb_command_createntsharedobject { + struct dxgkvmb_command_vm_to_host hdr; + struct d3dkmthandle object; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroyntsharedobject { + struct dxgkvmb_command_vm_to_host hdr; + struct d3dkmthandle shared_handle; +}; + /* Returns ntstatus */ struct dxgkvmb_command_setiospaceregion { struct dxgkvmb_command_vm_to_host hdr; @@ -305,6 +320,21 @@ struct dxgkvmb_command_createallocation { /* u8 priv_drv_data[] for each alloc_info */ }; =20 +struct dxgkvmb_command_openresource { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + bool nt_security_sharing; + struct d3dkmthandle global_share; + u32 allocation_count; + u32 total_priv_drv_data_size; +}; + +struct dxgkvmb_command_openresource_return { + struct d3dkmthandle resource; + struct ntstatus status; +/* struct d3dkmthandle allocation[allocation_count]; */ +}; + struct dxgkvmb_command_getstandardallocprivdata { struct dxgkvmb_command_vgpu_to_host hdr; enum d3dkmdt_standardallocationtype alloc_type; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 0025e1ee2d4d..abb64f6c3a59 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -36,8 +36,35 @@ static char *errorstr(int ret) } #endif =20 +static int dxgsharedresource_release(struct inode *inode, struct file *fil= e) +{ + struct dxgsharedresource *resource =3D file->private_data; + + DXG_TRACE("Release resource: %p", resource); + mutex_lock(&resource->fd_mutex); + kref_get(&resource->sresource_kref); + resource->host_shared_handle_nt_reference--; + if (resource->host_shared_handle_nt_reference =3D=3D 0) { + if (resource->host_shared_handle_nt.v) { + dxgvmb_send_destroy_nt_shared_object( + resource->host_shared_handle_nt); + DXG_TRACE("Resource host_handle_nt destroyed: %x", + resource->host_shared_handle_nt.v); + resource->host_shared_handle_nt.v =3D 0; + } + kref_put(&resource->sresource_kref, dxgsharedresource_destroy); + } + mutex_unlock(&resource->fd_mutex); + kref_put(&resource->sresource_kref, dxgsharedresource_destroy); + return 0; +} + +static const struct file_operations dxg_resource_fops =3D { + .release =3D dxgsharedresource_release, +}; + static int dxgkio_open_adapter_from_luid(struct dxgprocess *process, - void *__user inargs) + void *__user inargs) { struct d3dkmt_openadapterfromluid args; int ret; @@ -212,6 +239,98 @@ dxgkp_enum_adapters(struct dxgprocess *process, return ret; } =20 +static int dxgsharedresource_seal(struct dxgsharedresource *shared_resourc= e) +{ + int ret =3D 0; + int i =3D 0; + u8 *private_data; + u32 data_size; + struct dxgresource *resource; + struct dxgallocation *alloc; + + DXG_TRACE("Sealing resource: %p", shared_resource); + + down_write(&shared_resource->adapter->shared_resource_list_lock); + if (shared_resource->sealed) { + DXG_TRACE("Resource already sealed"); + goto cleanup; + } + shared_resource->sealed =3D 1; + if (!list_empty(&shared_resource->resource_list_head)) { + resource =3D + list_first_entry(&shared_resource->resource_list_head, + struct dxgresource, + shared_resource_list_entry); + DXG_TRACE("First resource: %p", resource); + mutex_lock(&resource->resource_mutex); + list_for_each_entry(alloc, &resource->alloc_list_head, + alloc_list_entry) { + DXG_TRACE("Resource alloc: %p %d", alloc, + alloc->priv_drv_data->data_size); + shared_resource->allocation_count++; + shared_resource->alloc_private_data_size +=3D + alloc->priv_drv_data->data_size; + if (shared_resource->alloc_private_data_size < + alloc->priv_drv_data->data_size) { + DXG_ERR("alloc private data overflow"); + ret =3D -EINVAL; + goto cleanup1; + } + } + if (shared_resource->alloc_private_data_size =3D=3D 0) { + ret =3D -EINVAL; + goto cleanup1; + } + shared_resource->alloc_private_data =3D + vzalloc(shared_resource->alloc_private_data_size); + if (shared_resource->alloc_private_data =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup1; + } + shared_resource->alloc_private_data_sizes =3D + vzalloc(sizeof(u32)*shared_resource->allocation_count); + if (shared_resource->alloc_private_data_sizes =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup1; + } + private_data =3D shared_resource->alloc_private_data; + data_size =3D shared_resource->alloc_private_data_size; + i =3D 0; + list_for_each_entry(alloc, &resource->alloc_list_head, + alloc_list_entry) { + u32 alloc_data_size =3D alloc->priv_drv_data->data_size; + + if (alloc_data_size) { + if (data_size < alloc_data_size) { + dev_err(DXGDEV, + "Invalid private data size"); + ret =3D -EINVAL; + goto cleanup1; + } + shared_resource->alloc_private_data_sizes[i] =3D + alloc_data_size; + memcpy(private_data, + alloc->priv_drv_data->data, + alloc_data_size); + vfree(alloc->priv_drv_data); + alloc->priv_drv_data =3D NULL; + private_data +=3D alloc_data_size; + data_size -=3D alloc_data_size; + } + i++; + } + if (data_size !=3D 0) { + DXG_ERR("Data size mismatch"); + ret =3D -EINVAL; + } +cleanup1: + mutex_unlock(&resource->resource_mutex); + } +cleanup: + up_write(&shared_resource->adapter->shared_resource_list_lock); + return ret; +} + static int dxgkio_enum_adapters(struct dxgprocess *process, void *__user inargs) { @@ -803,6 +922,7 @@ dxgkio_create_allocation(struct dxgprocess *process, vo= id *__user inargs) u32 alloc_info_size =3D 0; struct dxgresource *resource =3D NULL; struct dxgallocation **dxgalloc =3D NULL; + struct dxgsharedresource *shared_resource =3D NULL; bool resource_mutex_acquired =3D false; u32 standard_alloc_priv_data_size =3D 0; void *standard_alloc_priv_data =3D NULL; @@ -973,6 +1093,76 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) } resource->private_runtime_handle =3D args.private_runtime_resource_handle; + if (args.flags.create_shared) { + if (!args.flags.nt_security_sharing) { + dev_err(DXGDEV, + "nt_security_sharing must be set"); + ret =3D -EINVAL; + goto cleanup; + } + shared_resource =3D dxgsharedresource_create(adapter); + if (shared_resource =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + shared_resource->runtime_private_data_size =3D + args.priv_drv_data_size; + shared_resource->resource_private_data_size =3D + args.priv_drv_data_size; + + shared_resource->runtime_private_data_size =3D + args.private_runtime_data_size; + shared_resource->resource_private_data_size =3D + args.priv_drv_data_size; + dxgsharedresource_add_resource(shared_resource, + resource); + if (args.flags.standard_allocation) { + shared_resource->resource_private_data =3D + res_priv_data; + shared_resource->resource_private_data_size =3D + res_priv_data_size; + res_priv_data =3D NULL; + } + if (args.private_runtime_data_size) { + shared_resource->runtime_private_data =3D + vzalloc(args.private_runtime_data_size); + if (shared_resource->runtime_private_data =3D=3D + NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user( + shared_resource->runtime_private_data, + args.private_runtime_data, + args.private_runtime_data_size); + if (ret) { + dev_err(DXGDEV, + "failed to copy runtime data"); + ret =3D -EINVAL; + goto cleanup; + } + } + if (args.priv_drv_data_size && + !args.flags.standard_allocation) { + shared_resource->resource_private_data =3D + vzalloc(args.priv_drv_data_size); + if (shared_resource->resource_private_data =3D=3D + NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user( + shared_resource->resource_private_data, + args.priv_drv_data, + args.priv_drv_data_size); + if (ret) { + dev_err(DXGDEV, + "failed to copy res data"); + ret =3D -EINVAL; + goto cleanup; + } + } + } } else { if (args.resource.v) { /* Adding new allocations to the given resource */ @@ -991,6 +1181,12 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) ret =3D -EINVAL; goto cleanup; } + if (resource->shared_owner && + resource->shared_owner->sealed) { + DXG_ERR("Resource is sealed"); + ret =3D -EINVAL; + goto cleanup; + } /* Synchronize with resource destruction */ mutex_lock(&resource->resource_mutex); if (!dxgresource_is_active(resource)) { @@ -1092,9 +1288,16 @@ dxgkio_create_allocation(struct dxgprocess *process,= void *__user inargs) } } if (resource && args.flags.create_resource) { + if (shared_resource) { + dxgsharedresource_remove_resource + (shared_resource, resource); + } dxgresource_destroy(resource); } } + if (shared_resource) + kref_put(&shared_resource->sresource_kref, + dxgsharedresource_destroy); if (dxgalloc) vfree(dxgalloc); if (standard_alloc_priv_data) @@ -1140,6 +1343,10 @@ static int validate_alloc(struct dxgallocation *allo= c0, fail_reason =3D 4; goto cleanup; } + if (alloc->owner.resource->shared_owner) { + fail_reason =3D 5; + goto cleanup; + } } else { if (alloc->owner.device !=3D device) { fail_reason =3D 6; @@ -2146,6 +2353,582 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proc= ess, void *__user inargs) return ret; } =20 +static int +dxgsharedresource_get_host_nt_handle(struct dxgsharedresource *resource, + struct dxgprocess *process, + struct d3dkmthandle objecthandle) +{ + int ret =3D 0; + + mutex_lock(&resource->fd_mutex); + if (resource->host_shared_handle_nt_reference =3D=3D 0) { + ret =3D dxgvmb_send_create_nt_shared_object(process, + objecthandle, + &resource->host_shared_handle_nt); + if (ret < 0) + goto cleanup; + DXG_TRACE("Resource host_shared_handle_ht: %x", + resource->host_shared_handle_nt.v); + kref_get(&resource->sresource_kref); + } + resource->host_shared_handle_nt_reference++; +cleanup: + mutex_unlock(&resource->fd_mutex); + return ret; +} + +enum dxg_sharedobject_type { + DXG_SHARED_RESOURCE +}; + +static int get_object_fd(enum dxg_sharedobject_type type, + void *object, int *fdout) +{ + struct file *file; + int fd; + + fd =3D get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + DXG_ERR("get_unused_fd_flags failed: %x", fd); + return -ENOTRECOVERABLE; + } + + switch (type) { + case DXG_SHARED_RESOURCE: + file =3D anon_inode_getfile("dxgresource", + &dxg_resource_fops, object, 0); + break; + default: + return -EINVAL; + }; + if (IS_ERR(file)) { + DXG_ERR("anon_inode_getfile failed: %x", fd); + put_unused_fd(fd); + return -ENOTRECOVERABLE; + } + + fd_install(fd, file); + *fdout =3D fd; + return 0; +} + +static int +dxgkio_share_objects(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_shareobjects args; + enum hmgrentry_type object_type; + struct dxgsyncobject *syncobj =3D NULL; + struct dxgresource *resource =3D NULL; + struct dxgsharedresource *shared_resource =3D NULL; + struct d3dkmthandle *handles =3D NULL; + int object_fd =3D -1; + void *obj =3D NULL; + u32 handle_size; + int ret; + u64 tmp =3D 0; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.object_count =3D=3D 0 || args.object_count > 1) { + DXG_ERR("invalid object count %d", args.object_count); + ret =3D -EINVAL; + goto cleanup; + } + + handle_size =3D args.object_count * sizeof(struct d3dkmthandle); + + handles =3D vzalloc(handle_size); + if (handles =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user(handles, args.objects, handle_size); + if (ret) { + DXG_ERR("failed to copy object handles"); + ret =3D -EINVAL; + goto cleanup; + } + + DXG_TRACE("Sharing handle: %x", handles[0].v); + + hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); + object_type =3D hmgrtable_get_object_type(&process->handle_table, + handles[0]); + obj =3D hmgrtable_get_object(&process->handle_table, handles[0]); + if (obj =3D=3D NULL) { + DXG_ERR("invalid object handle %x", handles[0].v); + ret =3D -EINVAL; + } else { + switch (object_type) { + case HMGRENTRY_TYPE_DXGRESOURCE: + resource =3D obj; + if (resource->shared_owner) { + kref_get(&resource->resource_kref); + shared_resource =3D resource->shared_owner; + } else { + resource =3D NULL; + DXG_ERR("resource object shared"); + ret =3D -EINVAL; + } + break; + default: + DXG_ERR("invalid object type %d", object_type); + ret =3D -EINVAL; + break; + } + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED); + + if (ret < 0) + goto cleanup; + + switch (object_type) { + case HMGRENTRY_TYPE_DXGRESOURCE: + ret =3D get_object_fd(DXG_SHARED_RESOURCE, shared_resource, + &object_fd); + if (ret < 0) { + DXG_ERR("get_object_fd failed for resource"); + goto cleanup; + } + ret =3D dxgsharedresource_get_host_nt_handle(shared_resource, + process, handles[0]); + if (ret < 0) { + DXG_ERR("get_host_res_nt_handle failed"); + goto cleanup; + } + ret =3D dxgsharedresource_seal(shared_resource); + if (ret < 0) { + DXG_ERR("dxgsharedresource_seal failed"); + goto cleanup; + } + break; + default: + ret =3D -EINVAL; + break; + } + + if (ret < 0) + goto cleanup; + + DXG_TRACE("Object FD: %x", object_fd); + + tmp =3D (u64) object_fd; + + ret =3D copy_to_user(args.shared_handle, &tmp, sizeof(u64)); + if (ret < 0) + DXG_ERR("failed to copy shared handle"); + +cleanup: + if (ret < 0) { + if (object_fd >=3D 0) + put_unused_fd(object_fd); + } + + if (handles) + vfree(handles); + + if (syncobj) + kref_put(&syncobj->syncobj_kref, dxgsyncobject_release); + + if (resource) + kref_put(&resource->resource_kref, dxgresource_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_query_resource_info_nt(struct dxgprocess *process, void *__user ina= rgs) +{ + struct d3dkmt_queryresourceinfofromnthandle args; + int ret; + struct dxgdevice *device =3D NULL; + struct dxgsharedresource *shared_resource =3D NULL; + struct file *file =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + file =3D fget(args.nt_handle); + if (!file) { + DXG_ERR("failed to get file from handle: %llx", + args.nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + + if (file->f_op !=3D &dxg_resource_fops) { + DXG_ERR("invalid fd: %llx", args.nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + + shared_resource =3D file->private_data; + if (shared_resource =3D=3D NULL) { + DXG_ERR("invalid private data: %llx", args.nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + goto cleanup; + } + + ret =3D dxgsharedresource_seal(shared_resource); + if (ret < 0) + goto cleanup; + + args.private_runtime_data_size =3D + shared_resource->runtime_private_data_size; + args.resource_priv_drv_data_size =3D + shared_resource->resource_private_data_size; + args.allocation_count =3D shared_resource->allocation_count; + args.total_priv_drv_data_size =3D + shared_resource->alloc_private_data_size; + + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy output args"); + ret =3D -EINVAL; + } + +cleanup: + + if (file) + fput(file); + if (device) + dxgdevice_release_lock_shared(device); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +assign_resource_handles(struct dxgprocess *process, + struct dxgsharedresource *shared_resource, + struct d3dkmt_openresourcefromnthandle *args, + struct d3dkmthandle resource_handle, + struct dxgresource *resource, + struct dxgallocation **allocs, + struct d3dkmthandle *handles) +{ + int ret; + int i; + u8 *cur_priv_data; + u32 total_priv_data_size =3D 0; + struct d3dddi_openallocationinfo2 open_alloc_info =3D { }; + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(&process->handle_table, resource, + HMGRENTRY_TYPE_DXGRESOURCE, + resource_handle); + if (ret < 0) + goto cleanup; + resource->handle =3D resource_handle; + resource->handle_valid =3D 1; + cur_priv_data =3D args->total_priv_drv_data; + for (i =3D 0; i < args->allocation_count; i++) { + ret =3D hmgrtable_assign_handle(&process->handle_table, allocs[i], + HMGRENTRY_TYPE_DXGALLOCATION, + handles[i]); + if (ret < 0) + goto cleanup; + allocs[i]->alloc_handle =3D handles[i]; + allocs[i]->handle_valid =3D 1; + open_alloc_info.allocation =3D handles[i]; + if (shared_resource->alloc_private_data_sizes) + open_alloc_info.priv_drv_data_size =3D + shared_resource->alloc_private_data_sizes[i]; + else + open_alloc_info.priv_drv_data_size =3D 0; + + total_priv_data_size +=3D open_alloc_info.priv_drv_data_size; + open_alloc_info.priv_drv_data =3D cur_priv_data; + cur_priv_data +=3D open_alloc_info.priv_drv_data_size; + + ret =3D copy_to_user(&args->open_alloc_info[i], + &open_alloc_info, + sizeof(open_alloc_info)); + if (ret) { + DXG_ERR("failed to copy alloc info"); + ret =3D -EINVAL; + goto cleanup; + } + } + args->total_priv_drv_data_size =3D total_priv_data_size; +cleanup: + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + if (ret < 0) { + for (i =3D 0; i < args->allocation_count; i++) + dxgallocation_free_handle(allocs[i]); + dxgresource_free_handle(resource); + } + return ret; +} + +static int +open_resource(struct dxgprocess *process, + struct d3dkmt_openresourcefromnthandle *args, + __user struct d3dkmthandle *res_out, + __user u32 *total_driver_data_size_out) +{ + int ret =3D 0; + int i; + struct d3dkmthandle *alloc_handles =3D NULL; + int alloc_handles_size =3D sizeof(struct d3dkmthandle) * + args->allocation_count; + struct dxgsharedresource *shared_resource =3D NULL; + struct dxgresource *resource =3D NULL; + struct dxgallocation **allocs =3D NULL; + struct d3dkmthandle global_share =3D {}; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dkmthandle resource_handle =3D {}; + struct file *file =3D NULL; + + DXG_TRACE("Opening resource handle: %llx", args->nt_handle); + + file =3D fget(args->nt_handle); + if (!file) { + DXG_ERR("failed to get file from handle: %llx", + args->nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + if (file->f_op !=3D &dxg_resource_fops) { + DXG_ERR("invalid fd type: %llx", args->nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + shared_resource =3D file->private_data; + if (shared_resource =3D=3D NULL) { + DXG_ERR("invalid private data: %llx", args->nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + if (kref_get_unless_zero(&shared_resource->sresource_kref) =3D=3D 0) + shared_resource =3D NULL; + else + global_share =3D shared_resource->host_shared_handle_nt; + + if (shared_resource =3D=3D NULL) { + DXG_ERR("Invalid shared resource handle: %x", + (u32)args->nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + + DXG_TRACE("Shared resource: %p %x", shared_resource, + global_share.v); + + device =3D dxgprocess_device_by_handle(process, args->device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgsharedresource_seal(shared_resource); + if (ret < 0) + goto cleanup; + + if (args->allocation_count !=3D shared_resource->allocation_count || + args->private_runtime_data_size < + shared_resource->runtime_private_data_size || + args->resource_priv_drv_data_size < + shared_resource->resource_private_data_size || + args->total_priv_drv_data_size < + shared_resource->alloc_private_data_size) { + ret =3D -EINVAL; + DXG_ERR("Invalid data sizes"); + goto cleanup; + } + + alloc_handles =3D vzalloc(alloc_handles_size); + if (alloc_handles =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + allocs =3D vzalloc(sizeof(void *) * args->allocation_count); + if (allocs =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + resource =3D dxgresource_create(device); + if (resource =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + dxgsharedresource_add_resource(shared_resource, resource); + + for (i =3D 0; i < args->allocation_count; i++) { + allocs[i] =3D dxgallocation_create(process); + if (allocs[i] =3D=3D NULL) + goto cleanup; + ret =3D dxgresource_add_alloc(resource, allocs[i]); + if (ret < 0) + goto cleanup; + } + + ret =3D dxgvmb_send_open_resource(process, adapter, + device->handle, global_share, + args->allocation_count, + args->total_priv_drv_data_size, + &resource_handle, alloc_handles); + if (ret < 0) { + DXG_ERR("dxgvmb_send_open_resource failed"); + goto cleanup; + } + + if (shared_resource->runtime_private_data_size) { + ret =3D copy_to_user(args->private_runtime_data, + shared_resource->runtime_private_data, + shared_resource->runtime_private_data_size); + if (ret) { + DXG_ERR("failed to copy runtime data"); + ret =3D -EINVAL; + goto cleanup; + } + } + + if (shared_resource->resource_private_data_size) { + ret =3D copy_to_user(args->resource_priv_drv_data, + shared_resource->resource_private_data, + shared_resource->resource_private_data_size); + if (ret) { + DXG_ERR("failed to copy resource data"); + ret =3D -EINVAL; + goto cleanup; + } + } + + if (shared_resource->alloc_private_data_size) { + ret =3D copy_to_user(args->total_priv_drv_data, + shared_resource->alloc_private_data, + shared_resource->alloc_private_data_size); + if (ret) { + DXG_ERR("failed to copy alloc data"); + ret =3D -EINVAL; + goto cleanup; + } + } + + ret =3D assign_resource_handles(process, shared_resource, args, + resource_handle, resource, allocs, + alloc_handles); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(res_out, &resource_handle, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy resource handle to user"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D copy_to_user(total_driver_data_size_out, + &args->total_priv_drv_data_size, sizeof(u32)); + if (ret) { + DXG_ERR("failed to copy total driver data size"); + ret =3D -EINVAL; + } + +cleanup: + + if (ret < 0) { + if (resource_handle.v) { + struct d3dkmt_destroyallocation2 tmp =3D { }; + + tmp.flags.assume_not_in_use =3D 1; + tmp.device =3D args->device; + tmp.resource =3D resource_handle; + ret =3D dxgvmb_send_destroy_allocation(process, device, + &tmp, NULL); + } + if (resource) + dxgresource_destroy(resource); + } + + if (file) + fput(file); + if (allocs) + vfree(allocs); + if (shared_resource) + kref_put(&shared_resource->sresource_kref, + dxgsharedresource_destroy); + if (alloc_handles) + vfree(alloc_handles); + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + dxgdevice_release_lock_shared(device); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + return ret; +} + +static int +dxgkio_open_resource_nt(struct dxgprocess *process, + void *__user inargs) +{ + struct d3dkmt_openresourcefromnthandle args; + struct d3dkmt_openresourcefromnthandle *__user args_user =3D inargs; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D open_resource(process, &args, + &args_user->resource, + &args_user->total_priv_drv_data_size); + +cleanup: + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static struct ioctl_desc ioctls[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -2215,10 +2998,11 @@ static struct ioctl_desc ioctls[] =3D { /* 0x3c */ {}, /* 0x3d */ {}, /* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3}, -/* 0x3f */ {}, +/* 0x3f */ {dxgkio_share_objects, LX_DXSHAREOBJECTS}, /* 0x40 */ {}, -/* 0x41 */ {}, -/* 0x42 */ {}, +/* 0x41 */ {dxgkio_query_resource_info_nt, + LX_DXQUERYRESOURCEINFOFROMNTHANDLE}, +/* 0x42 */ {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE}, /* 0x43 */ {}, /* 0x44 */ {}, /* 0x45 */ {}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 39055b0c1069..f74564cf7ee9 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -682,6 +682,94 @@ enum d3dkmt_deviceexecution_state { _D3DKMT_DEVICEEXECUTION_ERROR_DMAPAGEFAULT =3D 7, }; =20 +struct d3dddi_openallocationinfo2 { + struct d3dkmthandle allocation; +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + __u32 priv_drv_data_size; + __u64 gpu_va; + __u64 reserved[6]; +}; + +struct d3dkmt_openresourcefromnthandle { + struct d3dkmthandle device; + __u32 reserved; + __u64 nt_handle; + __u32 allocation_count; + __u32 reserved1; +#ifdef __KERNEL__ + struct d3dddi_openallocationinfo2 *open_alloc_info; +#else + __u64 open_alloc_info; +#endif + int private_runtime_data_size; + __u32 reserved2; +#ifdef __KERNEL__ + void *private_runtime_data; +#else + __u64 private_runtime_data; +#endif + __u32 resource_priv_drv_data_size; + __u32 reserved3; +#ifdef __KERNEL__ + void *resource_priv_drv_data; +#else + __u64 resource_priv_drv_data; +#endif + __u32 total_priv_drv_data_size; +#ifdef __KERNEL__ + void *total_priv_drv_data; +#else + __u64 total_priv_drv_data; +#endif + struct d3dkmthandle resource; + struct d3dkmthandle keyed_mutex; +#ifdef __KERNEL__ + void *keyed_mutex_private_data; +#else + __u64 keyed_mutex_private_data; +#endif + __u32 keyed_mutex_private_data_size; + struct d3dkmthandle sync_object; +}; + +struct d3dkmt_queryresourceinfofromnthandle { + struct d3dkmthandle device; + __u32 reserved; + __u64 nt_handle; +#ifdef __KERNEL__ + void *private_runtime_data; +#else + __u64 private_runtime_data; +#endif + __u32 private_runtime_data_size; + __u32 total_priv_drv_data_size; + __u32 resource_priv_drv_data_size; + __u32 allocation_count; +}; + +struct d3dkmt_shareobjects { + __u32 object_count; + __u32 reserved; +#ifdef __KERNEL__ + const struct d3dkmthandle *objects; + void *object_attr; /* security attributes */ +#else + __u64 objects; + __u64 object_attr; +#endif + __u32 desired_access; + __u32 reserved1; +#ifdef __KERNEL__ + __u64 *shared_handle; /* output file descriptors */ +#else + __u64 shared_handle; +#endif +}; + union d3dkmt_enumadapters_filter { struct { __u64 include_compute_only:1; @@ -747,5 +835,13 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x3b, struct d3dkmt_waitforsynchronizationobjectfromgpu) #define LX_DXENUMADAPTERS3 \ _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) +#define LX_DXSHAREOBJECTS \ + _IOWR(0x47, 0x3f, struct d3dkmt_shareobjects) +#define LX_DXOPENSYNCOBJECTFROMNTHANDLE2 \ + _IOWR(0x47, 0x40, struct d3dkmt_opensyncobjectfromnthandle2) +#define LX_DXQUERYRESOURCEINFOFROMNTHANDLE \ + _IOWR(0x47, 0x41, struct d3dkmt_queryresourceinfofromnthandle) +#define LX_DXOPENRESOURCEFROMNTHANDLE \ + _IOWR(0x47, 0x42, struct d3dkmt_openresourcefromnthandle) =20 #endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f48.google.com (mail-wr1-f48.google.com [209.85.221.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9B1BA3F99E8 for ; Thu, 19 Mar 2026 20:25:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951935; cv=none; b=FOTgx/owxoQrT52+DqB1L050pit0g/Bsql6FcIKaHCzAaJp/3CWW34vXIb+qLUPZbkC7QB09c+XUhQPEdlCxgVjpDAUKn2b8nYdVfqFMe0FWzAB/ewwkLGPtNx0UkAXE2YkTLQqlov9hzRyWYNL+PkbjLQF6fIuQMU4+t8jtdi8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951935; c=relaxed/simple; bh=a2vd79V0AjDuy4oueQBrEIUprc5m/j/RcDkGYHdH4kg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F42yZR8iuZiu9d+eGh3rr+iW8fmejYqRS6zGQ4+F2u2zdXeEKDUkH5ADRckI/OrL0t5pZdQmbgIdIu2/rN7/J5tzEEKkfEQtR35bUyEparYfK+i6n6MSGueL8F0YdK/FAN8VkUzrZURD/D6AD56WPO4A8lgKUdifZ6HcvqruJoI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=a7eqlgL1; arc=none smtp.client-ip=209.85.221.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="a7eqlgL1" Received: by mail-wr1-f48.google.com with SMTP id ffacd0b85a97d-43b48ac2727so976293f8f.3 for ; Thu, 19 Mar 2026 13:25:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951928; x=1774556728; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=5MsMqVi/jx9f6CqF4yg4o+tJzdQrpKkBPp9sDJfveuE=; b=a7eqlgL1FOgKR0QFdHxiRrT6GUwYSSPEaac9N2RJ1VwguRLr8z/PQ8bEqM7+CrkJTk M6SHjczIi6SNttAJ31TSfEhsc1qCjxPyA9zK3Pvui2h3QFktZyvY+IxJ/KmRbvqBvBLq sc21n/u7CfxwJmAmjTIYWvTZmpQ+B2umzNbf8NXD2w1/yMSBKWncO6KPBEG6q2NuVWHh x62XgmzK6AXNFLk8u5wmBs/IJpEGKvIPrJ7DNDdN6hKbSmNN357Lar7h3B8rS0FfwLZC 232gOxmRfHUprKiFmxLIR+99A1xGYCKvLWr+f9QrzKaib05mdOMQXTKlOiLNl3JCTlU/ prTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951928; x=1774556728; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=5MsMqVi/jx9f6CqF4yg4o+tJzdQrpKkBPp9sDJfveuE=; b=oM0YuRH4kzKzHqKaEZHtovFjAoDMmPkAsEoOLq2CNLWRXBfpRQI7XLaYmR8Nh5ruAV EbyGrvN1tRAsascuUII4tyST78yX76hYKE8aImekTwX00PpZ+knW+la2Mv+XJPBBjI4h yQxFNO2pww0v3GdVSJ9tTAMWzRqKKEg8s/N67oisAyOEpa8Irf8iAq+Q/82+xUhWZ3ky r2WHUFDjQ0mtxrw1EnBreyzrUq1H010cAM186akGWBTLUnUQG08+yayy+M2Il0OcZfwr xqOaIAxpBgjudmz2yJvE/yRqilVZUYTJdftiapQHQbvWUTGVqh6t5LlIx7TZoE9f42Ti 6FIA== X-Gm-Message-State: AOJu0YxUr2p5v0Ybe5v/ubECmOA2JevTszk9QgAdyvIczC75YJFw13C/ YTwP1lDC8h3SA1gORPUPnwJ2cbuNO1DtlcpNYw2pcXrOzR0k9ZADKZ8U X-Gm-Gg: ATEYQzxqa0Yxcb2hREemS33LU5ujEex2gp3BbHp1q465qYC6OdTFO1KJY65vB3FqAp4 PrfnbTb+u5AjY7gURs0qoGZdCWoQiIBk/pjK54wdlbmt79cvMPblc+pRuqW3IDj5iURNeMPhAee EJ/Ahdz2UpZd/iHt9zT3TUfos5QiIRCyt00ydvVhuKNj8rF203VvOo2ORAXQJQXYl7HrD0EJBHq uckybr/M73HMISnjBLJptqTmOFTO8yRSm/S8+SU0euyooq2p/ujYwC2Jc1kcSOVfsYz6ZXTtweh oG19rKCJ33VoyozGgGN9tXCVR6sL45LN/Ls/RlDQEfBcrTQiMUYGUfpqQA/Hk2GporL1zRXDncy NcJQ5jn2liW8Pa5Imah9MZumRvIbFjyTff1KqSj/xtLMdxS+sGeBhhm4uu0cTWpwRh9Cz+pJfLd KffR36LWQccddW8gCLtzpPnLHES4ztRrC+kjFxw0IdezqqZz3j X-Received: by 2002:a05:6000:1788:b0:439:d8e2:9a40 with SMTP id ffacd0b85a97d-43b644851a3mr1197417f8f.55.1773951927437; Thu, 19 Mar 2026 13:25:27 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.26 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:26 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 12/55] drivers: hv: dxgkrnl: Sharing of sync objects Date: Thu, 19 Mar 2026 20:24:26 +0000 Message-ID: <20260319202509.63802-13-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement creation of a shared sync objects and the ioctl for sharing dxgsyncobject objects between processes in the virtual machine. Sync objects are shared using file descriptor (FD) handles. The name "NT handle" is used to be compatible with Windows implementation. An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The created FD handle could be sent to another process using any Linux API. To use a shared sync object in other ioctls, the object needs to be opened using its FD handle. A sync object is opened by the LX_DXOPENSYNCOBJECTFROMNTHANDLE2 ioctl, which returns a d3dkmthandle value. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 181 ++++++++++- drivers/hv/dxgkrnl/dxgkrnl.h | 96 ++++++ drivers/hv/dxgkrnl/dxgmodule.c | 1 + drivers/hv/dxgkrnl/dxgprocess.c | 4 + drivers/hv/dxgkrnl/dxgvmbus.c | 221 +++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 35 ++ drivers/hv/dxgkrnl/ioctl.c | 556 +++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 93 ++++++ 8 files changed, 1181 insertions(+), 6 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index 26fce9aba4f3..f59173f13559 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -171,6 +171,26 @@ void dxgadapter_remove_shared_resource(struct dxgadapt= er *adapter, up_write(&adapter->shared_resource_list_lock); } =20 +void dxgadapter_add_shared_syncobj(struct dxgadapter *adapter, + struct dxgsharedsyncobject *object) +{ + down_write(&adapter->shared_resource_list_lock); + list_add_tail(&object->adapter_shared_syncobj_list_entry, + &adapter->adapter_shared_syncobj_list_head); + up_write(&adapter->shared_resource_list_lock); +} + +void dxgadapter_remove_shared_syncobj(struct dxgadapter *adapter, + struct dxgsharedsyncobject *object) +{ + down_write(&adapter->shared_resource_list_lock); + if (object->adapter_shared_syncobj_list_entry.next) { + list_del(&object->adapter_shared_syncobj_list_entry); + object->adapter_shared_syncobj_list_entry.next =3D NULL; + } + up_write(&adapter->shared_resource_list_lock); +} + void dxgadapter_add_syncobj(struct dxgadapter *adapter, struct dxgsyncobject *object) { @@ -622,7 +642,7 @@ void dxgresource_destroy(struct dxgresource *resource) dxgallocation_destroy(alloc); } dxgdevice_remove_resource(device, resource); - shared_resource =3D resource->shared_owner; + shared_resource =3D resource->shared_owner; if (shared_resource) { dxgsharedresource_remove_resource(shared_resource, resource); @@ -736,6 +756,9 @@ struct dxgcontext *dxgcontext_create(struct dxgdevice *= device) */ void dxgcontext_destroy(struct dxgprocess *process, struct dxgcontext *con= text) { + struct dxghwqueue *hwqueue; + struct dxghwqueue *tmp; + DXG_TRACE("Destroying context %p", context); context->object_state =3D DXGOBJECTSTATE_DESTROYED; if (context->device) { @@ -747,6 +770,10 @@ void dxgcontext_destroy(struct dxgprocess *process, st= ruct dxgcontext *context) dxgdevice_remove_context(context->device, context); kref_put(&context->device->device_kref, dxgdevice_release); } + list_for_each_entry_safe(hwqueue, tmp, &context->hwqueue_list_head, + hwqueue_list_entry) { + dxghwqueue_destroy(process, hwqueue); + } kref_put(&context->context_kref, dxgcontext_release); } =20 @@ -773,6 +800,38 @@ void dxgcontext_release(struct kref *refcount) kfree(context); } =20 +int dxgcontext_add_hwqueue(struct dxgcontext *context, + struct dxghwqueue *hwqueue) +{ + int ret =3D 0; + + down_write(&context->hwqueue_list_lock); + if (dxgcontext_is_active(context)) + list_add_tail(&hwqueue->hwqueue_list_entry, + &context->hwqueue_list_head); + else + ret =3D -ENODEV; + up_write(&context->hwqueue_list_lock); + return ret; +} + +void dxgcontext_remove_hwqueue(struct dxgcontext *context, + struct dxghwqueue *hwqueue) +{ + if (hwqueue->hwqueue_list_entry.next) { + list_del(&hwqueue->hwqueue_list_entry); + hwqueue->hwqueue_list_entry.next =3D NULL; + } +} + +void dxgcontext_remove_hwqueue_safe(struct dxgcontext *context, + struct dxghwqueue *hwqueue) +{ + down_write(&context->hwqueue_list_lock); + dxgcontext_remove_hwqueue(context, hwqueue); + up_write(&context->hwqueue_list_lock); +} + struct dxgallocation *dxgallocation_create(struct dxgprocess *process) { struct dxgallocation *alloc; @@ -958,6 +1017,63 @@ void dxgprocess_adapter_remove_device(struct dxgdevic= e *device) mutex_unlock(&device->adapter_info->device_list_mutex); } =20 +struct dxgsharedsyncobject *dxgsharedsyncobj_create(struct dxgadapter *ada= pter, + struct dxgsyncobject *so) +{ + struct dxgsharedsyncobject *syncobj; + + syncobj =3D kzalloc(sizeof(*syncobj), GFP_KERNEL); + if (syncobj) { + kref_init(&syncobj->ssyncobj_kref); + INIT_LIST_HEAD(&syncobj->shared_syncobj_list_head); + syncobj->adapter =3D adapter; + syncobj->type =3D so->type; + syncobj->monitored_fence =3D so->monitored_fence; + dxgadapter_add_shared_syncobj(adapter, syncobj); + kref_get(&adapter->adapter_kref); + init_rwsem(&syncobj->syncobj_list_lock); + mutex_init(&syncobj->fd_mutex); + } + return syncobj; +} + +void dxgsharedsyncobj_release(struct kref *refcount) +{ + struct dxgsharedsyncobject *syncobj; + + syncobj =3D container_of(refcount, struct dxgsharedsyncobject, + ssyncobj_kref); + DXG_TRACE("Destroying shared sync object %p", syncobj); + if (syncobj->adapter) { + dxgadapter_remove_shared_syncobj(syncobj->adapter, + syncobj); + kref_put(&syncobj->adapter->adapter_kref, + dxgadapter_release); + } + kfree(syncobj); +} + +void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *shared, + struct dxgsyncobject *syncobj) +{ + DXG_TRACE("Add syncobj 0x%p 0x%p", shared, syncobj); + kref_get(&shared->ssyncobj_kref); + down_write(&shared->syncobj_list_lock); + list_add(&syncobj->shared_syncobj_list_entry, + &shared->shared_syncobj_list_head); + syncobj->shared_owner =3D shared; + up_write(&shared->syncobj_list_lock); +} + +void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *shared, + struct dxgsyncobject *syncobj) +{ + DXG_TRACE("Remove syncobj 0x%p", shared); + down_write(&shared->syncobj_list_lock); + list_del(&syncobj->shared_syncobj_list_entry); + up_write(&shared->syncobj_list_lock); +} + struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process, struct dxgdevice *device, struct dxgadapter *adapter, @@ -1091,7 +1207,70 @@ void dxgsyncobject_release(struct kref *refcount) struct dxgsyncobject *syncobj; =20 syncobj =3D container_of(refcount, struct dxgsyncobject, syncobj_kref); + if (syncobj->shared_owner) { + dxgsharedsyncobj_remove_syncobj(syncobj->shared_owner, + syncobj); + kref_put(&syncobj->shared_owner->ssyncobj_kref, + dxgsharedsyncobj_release); + } if (syncobj->host_event) kfree(syncobj->host_event); kfree(syncobj); } + +struct dxghwqueue *dxghwqueue_create(struct dxgcontext *context) +{ + struct dxgprocess *process =3D context->device->process; + struct dxghwqueue *hwqueue =3D kzalloc(sizeof(*hwqueue), GFP_KERNEL); + + if (hwqueue) { + kref_init(&hwqueue->hwqueue_kref); + hwqueue->context =3D context; + hwqueue->process =3D process; + hwqueue->device_handle =3D context->device->handle; + if (dxgcontext_add_hwqueue(context, hwqueue) < 0) { + kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release); + hwqueue =3D NULL; + } else { + kref_get(&context->context_kref); + } + } + return hwqueue; +} + +void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwq= ueue) +{ + DXG_TRACE("Destroyng hwqueue %p", hwqueue); + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + if (hwqueue->handle.v) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGHWQUEUE, + hwqueue->handle); + hwqueue->handle.v =3D 0; + } + if (hwqueue->progress_fence_sync_object.v) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_MONITOREDFENCE, + hwqueue->progress_fence_sync_object); + hwqueue->progress_fence_sync_object.v =3D 0; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (hwqueue->progress_fence_mapped_address) { + dxg_unmap_iospace(hwqueue->progress_fence_mapped_address, + PAGE_SIZE); + hwqueue->progress_fence_mapped_address =3D NULL; + } + dxgcontext_remove_hwqueue_safe(hwqueue->context, hwqueue); + + kref_put(&hwqueue->context->context_kref, dxgcontext_release); + kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release); +} + +void dxghwqueue_release(struct kref *refcount) +{ + struct dxghwqueue *hwqueue; + + hwqueue =3D container_of(refcount, struct dxghwqueue, hwqueue_kref); + kfree(hwqueue); +} diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 0336e1843223..0330352b9c06 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -40,6 +40,8 @@ struct dxgallocation; struct dxgresource; struct dxgsharedresource; struct dxgsyncobject; +struct dxgsharedsyncobject; +struct dxghwqueue; =20 /* * Driver private data. @@ -137,6 +139,18 @@ struct dxghosteventcpu { * "device" syncobject, because the belong to a device (dxgdevice). * Device syncobjects are inserted to a list in dxgdevice. * + * A syncobject can be "shared", meaning that it could be opened by many + * processes. + * + * Shared syncobjects are inserted to a list in its owner + * (dxgsharedsyncobject). + * A syncobject can be shared by using a global handle or by using + * "NT security handle". + * When global handle sharing is used, the handle is created durinig object + * creation. + * When "NT security" is used, the handle for sharing is create be calling + * dxgk_share_objects. On Linux "NT handle" is represented by a file + * descriptor. FD points to dxgsharedsyncobject. */ struct dxgsyncobject { struct kref syncobj_kref; @@ -146,6 +160,8 @@ struct dxgsyncobject { * List entry in dxgadapter for other objects */ struct list_head syncobj_list_entry; + /* List entry in the dxgsharedsyncobject object for shared synobjects */ + struct list_head shared_syncobj_list_entry; /* Adapter, the syncobject belongs to. NULL for stopped sync obejcts. */ struct dxgadapter *adapter; /* @@ -156,6 +172,8 @@ struct dxgsyncobject { struct dxgprocess *process; /* Used by D3DDDI_CPU_NOTIFICATION objects */ struct dxghosteventcpu *host_event; + /* Owner object for shared syncobjects */ + struct dxgsharedsyncobject *shared_owner; /* CPU virtual address of the fence value for "device" syncobjects */ void *mapped_address; /* Handle in the process handle table */ @@ -187,6 +205,41 @@ struct dxgvgpuchannel { struct hv_device *hdev; }; =20 +/* + * The object is used as parent of all sync objects, created for a shared + * syncobject. When a shared syncobject is created without NT security, the + * handle in the global handle table will point to this object. + */ +struct dxgsharedsyncobject { + struct kref ssyncobj_kref; + /* Referenced by file descriptors */ + int host_shared_handle_nt_reference; + /* Corresponding handle in the host global handle table */ + struct d3dkmthandle host_shared_handle; + /* + * When the sync object is shared by NT handle, this is the + * corresponding handle in the host + */ + struct d3dkmthandle host_shared_handle_nt; + /* Protects access to host_shared_handle_nt */ + struct mutex fd_mutex; + struct rw_semaphore syncobj_list_lock; + struct list_head shared_syncobj_list_head; + struct list_head adapter_shared_syncobj_list_entry; + struct dxgadapter *adapter; + enum d3dddi_synchronizationobject_type type; + u32 monitored_fence:1; +}; + +struct dxgsharedsyncobject *dxgsharedsyncobj_create(struct dxgadapter *ada= pter, + struct dxgsyncobject + *syncobj); +void dxgsharedsyncobj_release(struct kref *refcount); +void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *sharedsyncob= j, + struct dxgsyncobject *syncobj); +void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *sharedsyn= cobj, + struct dxgsyncobject *syncobj); + struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process, struct dxgdevice *device, struct dxgadapter *adapter, @@ -375,6 +428,8 @@ struct dxgadapter { struct list_head adapter_process_list_head; /* List of all dxgsharedresource objects */ struct list_head shared_resource_list_head; + /* List of all dxgsharedsyncobject objects */ + struct list_head adapter_shared_syncobj_list_head; /* List of all non-device dxgsyncobject objects */ struct list_head syncobj_list_head; /* This lock protects shared resource and syncobject lists */ @@ -402,6 +457,10 @@ void dxgadapter_release_lock_shared(struct dxgadapter = *adapter); int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter); void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter); void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter); +void dxgadapter_add_shared_syncobj(struct dxgadapter *adapter, + struct dxgsharedsyncobject *so); +void dxgadapter_remove_shared_syncobj(struct dxgadapter *adapter, + struct dxgsharedsyncobject *so); void dxgadapter_add_syncobj(struct dxgadapter *adapter, struct dxgsyncobject *so); void dxgadapter_remove_syncobj(struct dxgsyncobject *so); @@ -487,8 +546,32 @@ struct dxgcontext *dxgcontext_create(struct dxgdevice = *dev); void dxgcontext_destroy(struct dxgprocess *pr, struct dxgcontext *ctx); void dxgcontext_destroy_safe(struct dxgprocess *pr, struct dxgcontext *ctx= ); void dxgcontext_release(struct kref *refcount); +int dxgcontext_add_hwqueue(struct dxgcontext *ctx, + struct dxghwqueue *hq); +void dxgcontext_remove_hwqueue(struct dxgcontext *ctx, struct dxghwqueue *= hq); +void dxgcontext_remove_hwqueue_safe(struct dxgcontext *ctx, + struct dxghwqueue *hq); bool dxgcontext_is_active(struct dxgcontext *ctx); =20 +/* + * The object represent the execution hardware queue of a device. + */ +struct dxghwqueue { + /* entry in the context hw queue list */ + struct list_head hwqueue_list_entry; + struct kref hwqueue_kref; + struct dxgcontext *context; + struct dxgprocess *process; + struct d3dkmthandle progress_fence_sync_object; + struct d3dkmthandle handle; + struct d3dkmthandle device_handle; + void *progress_fence_mapped_address; +}; + +struct dxghwqueue *dxghwqueue_create(struct dxgcontext *ctx); +void dxghwqueue_destroy(struct dxgprocess *pr, struct dxghwqueue *hq); +void dxghwqueue_release(struct kref *refcount); + /* * A shared resource object is created to track the list of dxgresource ob= jects, * which are opened for the same underlying shared resource. @@ -720,9 +803,22 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess= *process, d3dkmt_waitforsynchronizationobjectfromcpu *args, u64 cpu_event); +int dxgvmb_send_create_hwqueue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_createhwqueue *args, + struct d3dkmt_createhwqueue *__user inargs, + struct dxghwqueue *hq); +int dxgvmb_send_destroy_hwqueue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle handle); int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); +int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process, + struct dxgvmbuschannel *channel, + struct d3dkmt_opensyncobjectfromnthandle2 + *args, + struct dxgsyncobject *syncobj); int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process, struct d3dkmthandle object, struct d3dkmthandle *shared_handle); diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 69e221613af9..8cbe1095599f 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -259,6 +259,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_= t *guid, =20 INIT_LIST_HEAD(&adapter->adapter_process_list_head); INIT_LIST_HEAD(&adapter->shared_resource_list_head); + INIT_LIST_HEAD(&adapter->adapter_shared_syncobj_list_head); INIT_LIST_HEAD(&adapter->syncobj_list_head); init_rwsem(&adapter->shared_resource_list_lock); adapter->pci_dev =3D dev; diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.c index a41985ef438d..4021084ebd78 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -277,6 +277,10 @@ struct dxgdevice *dxgprocess_device_by_object_handle(s= truct dxgprocess *process, device_handle =3D ((struct dxgcontext *)obj)->device_handle; break; + case HMGRENTRY_TYPE_DXGHWQUEUE: + device_handle =3D + ((struct dxghwqueue *)obj)->device_handle; + break; default: DXG_ERR("invalid handle type: %d", t); break; diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index b3a4377c8b0b..e83600945de1 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -712,6 +712,69 @@ int dxgvmb_send_destroy_process(struct d3dkmthandle pr= ocess) return ret; } =20 +int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process, + struct dxgvmbuschannel *channel, + struct d3dkmt_opensyncobjectfromnthandle2 + *args, + struct dxgsyncobject *syncobj) +{ + struct dxgkvmb_command_opensyncobject *command; + struct dxgkvmb_command_opensyncobject_return result =3D { }; + int ret; + struct dxgvmbusmsg msg; + + ret =3D init_message(&msg, NULL, process, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + command_vm_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_OPENSYNCOBJECT, + process->host_handle); + command->device =3D args->device; + command->global_sync_object =3D syncobj->shared_owner->host_shared_handle; + command->flags =3D args->flags; + if (syncobj->monitored_fence) + command->engine_affinity =3D + args->monitored_fence.engine_affinity; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + ret =3D dxgvmb_send_sync_msg(channel, msg.hdr, msg.size, + &result, sizeof(result)); + + dxgglobal_release_channel_lock(); + + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result.status); + if (ret < 0) + goto cleanup; + + args->sync_object =3D result.sync_object; + if (syncobj->monitored_fence) { + void *va =3D dxg_map_iospace(result.guest_cpu_physical_address, + PAGE_SIZE, PROT_READ | PROT_WRITE, + true); + if (va =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + args->monitored_fence.fence_value_cpu_va =3D va; + args->monitored_fence.fence_value_gpu_va =3D + result.gpu_virtual_address; + syncobj->mapped_address =3D va; + } + +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) @@ -2050,6 +2113,164 @@ int dxgvmb_send_wait_sync_object_gpu(struct dxgproc= ess *process, return ret; } =20 +int dxgvmb_send_create_hwqueue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_createhwqueue *args, + struct d3dkmt_createhwqueue *__user inargs, + struct dxghwqueue *hwqueue) +{ + struct dxgkvmb_command_createhwqueue *command =3D NULL; + u32 cmd_size =3D sizeof(struct dxgkvmb_command_createhwqueue); + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + if (args->priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("invalid private driver data size: %d", + args->priv_drv_data_size); + ret =3D -EINVAL; + goto cleanup; + } + + if (args->priv_drv_data_size) + cmd_size +=3D args->priv_drv_data_size - 1; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_CREATEHWQUEUE, + process->host_handle); + command->context =3D args->context; + command->flags =3D args->flags; + command->priv_drv_data_size =3D args->priv_drv_data_size; + if (args->priv_drv_data_size) { + ret =3D copy_from_user(command->priv_drv_data, + args->priv_drv_data, + args->priv_drv_data_size); + if (ret) { + DXG_ERR("failed to copy private data"); + ret =3D -EINVAL; + goto cleanup; + } + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + command, cmd_size); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(command->status); + if (ret < 0) { + DXG_ERR("dxgvmb_send_sync_msg failed: %x", + command->status.v); + goto cleanup; + } + + ret =3D hmgrtable_assign_handle_safe(&process->handle_table, hwqueue, + HMGRENTRY_TYPE_DXGHWQUEUE, + command->hwqueue); + if (ret < 0) + goto cleanup; + + ret =3D hmgrtable_assign_handle_safe(&process->handle_table, + NULL, + HMGRENTRY_TYPE_MONITOREDFENCE, + command->hwqueue_progress_fence); + if (ret < 0) + goto cleanup; + + hwqueue->handle =3D command->hwqueue; + hwqueue->progress_fence_sync_object =3D command->hwqueue_progress_fence; + + hwqueue->progress_fence_mapped_address =3D + dxg_map_iospace((u64)command->hwqueue_progress_fence_cpuva, + PAGE_SIZE, PROT_READ | PROT_WRITE, true); + if (hwqueue->progress_fence_mapped_address =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + ret =3D copy_to_user(&inargs->queue, &command->hwqueue, + sizeof(struct d3dkmthandle)); + if (ret < 0) { + DXG_ERR("failed to copy hwqueue handle"); + goto cleanup; + } + ret =3D copy_to_user(&inargs->queue_progress_fence, + &command->hwqueue_progress_fence, + sizeof(struct d3dkmthandle)); + if (ret < 0) { + DXG_ERR("failed to progress fence"); + goto cleanup; + } + ret =3D copy_to_user(&inargs->queue_progress_fence_cpu_va, + &hwqueue->progress_fence_mapped_address, + sizeof(inargs->queue_progress_fence_cpu_va)); + if (ret < 0) { + DXG_ERR("failed to copy fence cpu va"); + goto cleanup; + } + ret =3D copy_to_user(&inargs->queue_progress_fence_gpu_va, + &command->hwqueue_progress_fence_gpuva, + sizeof(u64)); + if (ret < 0) { + DXG_ERR("failed to copy fence gpu va"); + goto cleanup; + } + if (args->priv_drv_data_size) { + ret =3D copy_to_user(args->priv_drv_data, + command->priv_drv_data, + args->priv_drv_data_size); + if (ret < 0) + DXG_ERR("failed to copy private data"); + } + +cleanup: + if (ret < 0) { + DXG_ERR("failed %x", ret); + if (hwqueue->handle.v) { + hmgrtable_free_handle_safe(&process->handle_table, + HMGRENTRY_TYPE_DXGHWQUEUE, + hwqueue->handle); + hwqueue->handle.v =3D 0; + } + if (command && command->hwqueue.v) + dxgvmb_send_destroy_hwqueue(process, adapter, + command->hwqueue); + } + free_message(&msg, process); + return ret; +} + +int dxgvmb_send_destroy_hwqueue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle handle) +{ + int ret; + struct dxgkvmb_command_destroyhwqueue *command; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_DESTROYHWQUEUE, + process->host_handle); + command->hwqueue =3D handle; + + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 73d7adac60a1..2e2fd1ae5ec2 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -172,6 +172,21 @@ struct dxgkvmb_command_signalguestevent { bool dereference_event; }; =20 +struct dxgkvmb_command_opensyncobject { + struct dxgkvmb_command_vm_to_host hdr; + struct d3dkmthandle device; + struct d3dkmthandle global_sync_object; + u32 engine_affinity; + struct d3dddi_synchronizationobject_flags flags; +}; + +struct dxgkvmb_command_opensyncobject_return { + struct d3dkmthandle sync_object; + struct ntstatus status; + u64 gpu_virtual_address; + u64 guest_cpu_physical_address; +}; + /* * The command returns struct d3dkmthandle of a shared object for the * given pre-process object @@ -508,4 +523,24 @@ struct dxgkvmb_command_waitforsyncobjectfromgpu { /* struct d3dkmthandle ObjectHandles[object_count] */ }; =20 +/* Returns the same structure */ +struct dxgkvmb_command_createhwqueue { + struct dxgkvmb_command_vgpu_to_host hdr; + struct ntstatus status; + struct d3dkmthandle hwqueue; + struct d3dkmthandle hwqueue_progress_fence; + void *hwqueue_progress_fence_cpuva; + u64 hwqueue_progress_fence_gpuva; + struct d3dkmthandle context; + struct d3dddi_createhwqueueflags flags; + u32 priv_drv_data_size; + char priv_drv_data[1]; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroyhwqueue { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle hwqueue; +}; + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index abb64f6c3a59..3cfc1c40e0bb 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -36,6 +36,33 @@ static char *errorstr(int ret) } #endif =20 +static int dxgsyncobj_release(struct inode *inode, struct file *file) +{ + struct dxgsharedsyncobject *syncobj =3D file->private_data; + + DXG_TRACE("Release syncobj: %p", syncobj); + mutex_lock(&syncobj->fd_mutex); + kref_get(&syncobj->ssyncobj_kref); + syncobj->host_shared_handle_nt_reference--; + if (syncobj->host_shared_handle_nt_reference =3D=3D 0) { + if (syncobj->host_shared_handle_nt.v) { + dxgvmb_send_destroy_nt_shared_object( + syncobj->host_shared_handle_nt); + DXG_TRACE("Syncobj host_handle_nt destroyed: %x", + syncobj->host_shared_handle_nt.v); + syncobj->host_shared_handle_nt.v =3D 0; + } + kref_put(&syncobj->ssyncobj_kref, dxgsharedsyncobj_release); + } + mutex_unlock(&syncobj->fd_mutex); + kref_put(&syncobj->ssyncobj_kref, dxgsharedsyncobj_release); + return 0; +} + +static const struct file_operations dxg_syncobj_fops =3D { + .release =3D dxgsyncobj_release, +}; + static int dxgsharedresource_release(struct inode *inode, struct file *fil= e) { struct dxgsharedresource *resource =3D file->private_data; @@ -833,6 +860,156 @@ dxgkio_destroy_context(struct dxgprocess *process, vo= id *__user inargs) return ret; } =20 +static int +dxgkio_create_hwqueue(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_createhwqueue args; + struct dxgdevice *device =3D NULL; + struct dxgcontext *context =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct dxghwqueue *hwqueue =3D NULL; + int ret; + bool device_lock_acquired =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) + goto cleanup; + + device_lock_acquired =3D true; + + hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); + context =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED); + + if (context =3D=3D NULL) { + DXG_ERR("Invalid context handle %x", args.context.v); + ret =3D -EINVAL; + goto cleanup; + } + + hwqueue =3D dxghwqueue_create(context); + if (hwqueue =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_create_hwqueue(process, adapter, &args, + inargs, hwqueue); + +cleanup: + + if (ret < 0 && hwqueue) + dxghwqueue_destroy(process, hwqueue); + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device_lock_acquired) + dxgdevice_release_lock_shared(device); + + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int dxgkio_destroy_hwqueue(struct dxgprocess *process, + void *__user inargs) +{ + struct d3dkmt_destroyhwqueue args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxghwqueue *hwqueue =3D NULL; + struct d3dkmthandle device_handle =3D {}; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + hwqueue =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGHWQUEUE, + args.queue); + if (hwqueue) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGHWQUEUE, args.queue); + hwqueue->handle.v =3D 0; + device_handle =3D hwqueue->device_handle; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (hwqueue =3D=3D NULL) { + DXG_ERR("invalid hwqueue handle: %x", args.queue.v); + ret =3D -EINVAL; + goto cleanup; + } + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, device_handle); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_destroy_hwqueue(process, adapter, args.queue); + + dxghwqueue_destroy(process, hwqueue); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int get_standard_alloc_priv_data(struct dxgdevice *device, struct d3dkmt_createstandardallocation *alloc_info, @@ -1548,6 +1725,164 @@ dxgkio_destroy_allocation(struct dxgprocess *proces= s, void *__user inargs) return ret; } =20 +static int +dxgkio_submit_signal_to_hwqueue(struct dxgprocess *process, void *__user i= nargs) +{ + int ret; + struct d3dkmt_submitsignalsyncobjectstohwqueue args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dkmthandle hwqueue =3D {}; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.hwqueue_count > D3DDDI_MAX_BROADCAST_CONTEXT || + args.hwqueue_count =3D=3D 0) { + DXG_ERR("invalid hwqueue count: %d", + args.hwqueue_count); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.object_count > D3DDDI_MAX_OBJECT_SIGNALED || + args.object_count =3D=3D 0) { + DXG_ERR("invalid number of syncobjects: %d", + args.object_count); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D copy_from_user(&hwqueue, args.hwqueues, + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy hwqueue handle"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGHWQUEUE, + hwqueue); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_signal_sync_object(process, adapter, + args.flags, 0, zerohandle, + args.object_count, args.objects, + args.hwqueue_count, args.hwqueues, + args.object_count, + args.fence_values, NULL, + zerohandle); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_submit_wait_to_hwqueue(struct dxgprocess *process, void *__user ina= rgs) +{ + struct d3dkmt_submitwaitforsyncobjectstohwqueue args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + int ret; + struct d3dkmthandle *objects =3D NULL; + u32 object_size; + u64 *fences =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.object_count > D3DDDI_MAX_OBJECT_WAITED_ON || + args.object_count =3D=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + + object_size =3D sizeof(struct d3dkmthandle) * args.object_count; + objects =3D vzalloc(object_size); + if (objects =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user(objects, args.objects, object_size); + if (ret) { + DXG_ERR("failed to copy objects"); + ret =3D -EINVAL; + goto cleanup; + } + + object_size =3D sizeof(u64) * args.object_count; + fences =3D vzalloc(object_size); + if (fences =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + ret =3D copy_from_user(fences, args.fence_values, object_size); + if (ret) { + DXG_ERR("failed to copy fence values"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGHWQUEUE, + args.hwqueue); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_wait_sync_object_gpu(process, adapter, + args.hwqueue, args.object_count, + objects, fences, false); + +cleanup: + + if (objects) + vfree(objects); + if (fences) + vfree(fences); + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_create_sync_object(struct dxgprocess *process, void *__user inargs) { @@ -1558,6 +1893,7 @@ dxgkio_create_sync_object(struct dxgprocess *process,= void *__user inargs) struct eventfd_ctx *event =3D NULL; struct dxgsyncobject *syncobj =3D NULL; bool device_lock_acquired =3D false; + struct dxgsharedsyncobject *syncobjgbl =3D NULL; struct dxghosteventcpu *host_event =3D NULL; =20 ret =3D copy_from_user(&args, inargs, sizeof(args)); @@ -1618,6 +1954,22 @@ dxgkio_create_sync_object(struct dxgprocess *process= , void *__user inargs) if (ret < 0) goto cleanup; =20 + if (args.info.flags.shared) { + if (args.info.shared_handle.v =3D=3D 0) { + DXG_ERR("shared handle should not be 0"); + ret =3D -EINVAL; + goto cleanup; + } + syncobjgbl =3D dxgsharedsyncobj_create(device->adapter, syncobj); + if (syncobjgbl =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + dxgsharedsyncobj_add_syncobj(syncobjgbl, syncobj); + + syncobjgbl->host_shared_handle =3D args.info.shared_handle; + } + ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy output args"); @@ -1646,6 +1998,8 @@ dxgkio_create_sync_object(struct dxgprocess *process,= void *__user inargs) if (event) eventfd_ctx_put(event); } + if (syncobjgbl) + kref_put(&syncobjgbl->ssyncobj_kref, dxgsharedsyncobj_release); if (adapter) dxgadapter_release_lock_shared(adapter); if (device_lock_acquired) @@ -1700,6 +2054,140 @@ dxgkio_destroy_sync_object(struct dxgprocess *proce= ss, void *__user inargs) return ret; } =20 +static int +dxgkio_open_sync_object_nt(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_opensyncobjectfromnthandle2 args; + struct dxgsyncobject *syncobj =3D NULL; + struct dxgsharedsyncobject *syncobj_fd =3D NULL; + struct file *file =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dddi_synchronizationobject_flags flags =3D { }; + int ret; + bool device_lock_acquired =3D false; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + args.sync_object.v =3D 0; + + if (args.device.v) { + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + return -EINVAL; + goto cleanup; + } + } else { + DXG_ERR("device handle is missing"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) + goto cleanup; + + device_lock_acquired =3D true; + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + file =3D fget(args.nt_handle); + if (!file) { + DXG_ERR("failed to get file from handle: %llx", + args.nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + + if (file->f_op !=3D &dxg_syncobj_fops) { + DXG_ERR("invalid fd: %llx", args.nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + + syncobj_fd =3D file->private_data; + if (syncobj_fd =3D=3D NULL) { + DXG_ERR("invalid private data: %llx", args.nt_handle); + ret =3D -EINVAL; + goto cleanup; + } + + flags.shared =3D 1; + flags.nt_security_sharing =3D 1; + syncobj =3D dxgsyncobject_create(process, device, adapter, + syncobj_fd->type, flags); + if (syncobj =3D=3D NULL) { + DXG_ERR("failed to create sync object"); + ret =3D -ENOMEM; + goto cleanup; + } + + dxgsharedsyncobj_add_syncobj(syncobj_fd, syncobj); + + ret =3D dxgvmb_send_open_sync_object_nt(process, &dxgglobal->channel, + &args, syncobj); + if (ret < 0) { + DXG_ERR("failed to open sync object on host: %x", + syncobj_fd->host_shared_handle.v); + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(&process->handle_table, syncobj, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + args.sync_object); + if (ret >=3D 0) { + syncobj->handle =3D args.sync_object; + kref_get(&syncobj->syncobj_kref); + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret =3D=3D 0) + goto success; + DXG_ERR("failed to copy output args"); + +cleanup: + + if (syncobj) { + dxgsyncobject_destroy(process, syncobj); + syncobj =3D NULL; + } + + if (args.sync_object.v) + dxgvmb_send_destroy_sync_object(process, args.sync_object); + +success: + + if (file) + fput(file); + if (syncobj) + kref_put(&syncobj->syncobj_kref, dxgsyncobject_release); + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device_lock_acquired) + dxgdevice_release_lock_shared(device); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_signal_sync_object(struct dxgprocess *process, void *__user inargs) { @@ -2353,6 +2841,30 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proce= ss, void *__user inargs) return ret; } =20 +static int +dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj, + struct dxgprocess *process, + struct d3dkmthandle objecthandle) +{ + int ret =3D 0; + + mutex_lock(&syncobj->fd_mutex); + if (syncobj->host_shared_handle_nt_reference =3D=3D 0) { + ret =3D dxgvmb_send_create_nt_shared_object(process, + objecthandle, + &syncobj->host_shared_handle_nt); + if (ret < 0) + goto cleanup; + DXG_TRACE("Host_shared_handle_ht: %x", + syncobj->host_shared_handle_nt.v); + kref_get(&syncobj->ssyncobj_kref); + } + syncobj->host_shared_handle_nt_reference++; +cleanup: + mutex_unlock(&syncobj->fd_mutex); + return ret; +} + static int dxgsharedresource_get_host_nt_handle(struct dxgsharedresource *resource, struct dxgprocess *process, @@ -2378,6 +2890,7 @@ dxgsharedresource_get_host_nt_handle(struct dxgshared= resource *resource, } =20 enum dxg_sharedobject_type { + DXG_SHARED_SYNCOBJECT, DXG_SHARED_RESOURCE }; =20 @@ -2394,6 +2907,10 @@ static int get_object_fd(enum dxg_sharedobject_type = type, } =20 switch (type) { + case DXG_SHARED_SYNCOBJECT: + file =3D anon_inode_getfile("dxgsyncobj", + &dxg_syncobj_fops, object, 0); + break; case DXG_SHARED_RESOURCE: file =3D anon_inode_getfile("dxgresource", &dxg_resource_fops, object, 0); @@ -2419,6 +2936,7 @@ dxgkio_share_objects(struct dxgprocess *process, void= *__user inargs) enum hmgrentry_type object_type; struct dxgsyncobject *syncobj =3D NULL; struct dxgresource *resource =3D NULL; + struct dxgsharedsyncobject *shared_syncobj =3D NULL; struct dxgsharedresource *shared_resource =3D NULL; struct d3dkmthandle *handles =3D NULL; int object_fd =3D -1; @@ -2465,6 +2983,17 @@ dxgkio_share_objects(struct dxgprocess *process, voi= d *__user inargs) ret =3D -EINVAL; } else { switch (object_type) { + case HMGRENTRY_TYPE_DXGSYNCOBJECT: + syncobj =3D obj; + if (syncobj->shared) { + kref_get(&syncobj->syncobj_kref); + shared_syncobj =3D syncobj->shared_owner; + } else { + DXG_ERR("sync object is not shared"); + syncobj =3D NULL; + ret =3D -EINVAL; + } + break; case HMGRENTRY_TYPE_DXGRESOURCE: resource =3D obj; if (resource->shared_owner) { @@ -2488,6 +3017,21 @@ dxgkio_share_objects(struct dxgprocess *process, voi= d *__user inargs) goto cleanup; =20 switch (object_type) { + case HMGRENTRY_TYPE_DXGSYNCOBJECT: + ret =3D get_object_fd(DXG_SHARED_SYNCOBJECT, shared_syncobj, + &object_fd); + if (ret < 0) { + DXG_ERR("get_object_fd failed for sync object"); + goto cleanup; + } + ret =3D dxgsharedsyncobj_get_host_nt_handle(shared_syncobj, + process, + handles[0]); + if (ret < 0) { + DXG_ERR("get_host_nt_handle failed"); + goto cleanup; + } + break; case HMGRENTRY_TYPE_DXGRESOURCE: ret =3D get_object_fd(DXG_SHARED_RESOURCE, shared_resource, &object_fd); @@ -2954,10 +3498,10 @@ static struct ioctl_desc ioctls[] =3D { /* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER}, /* 0x16 */ {}, /* 0x17 */ {}, -/* 0x18 */ {}, +/* 0x18 */ {dxgkio_create_hwqueue, LX_DXCREATEHWQUEUE}, /* 0x19 */ {dxgkio_destroy_device, LX_DXDESTROYDEVICE}, /* 0x1a */ {}, -/* 0x1b */ {}, +/* 0x1b */ {dxgkio_destroy_hwqueue, LX_DXDESTROYHWQUEUE}, /* 0x1c */ {}, /* 0x1d */ {dxgkio_destroy_sync_object, LX_DXDESTROYSYNCHRONIZATIONOBJECT}, /* 0x1e */ {}, @@ -2986,8 +3530,10 @@ static struct ioctl_desc ioctls[] =3D { /* 0x33 */ {dxgkio_signal_sync_object_gpu2, LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2}, /* 0x34 */ {}, -/* 0x35 */ {}, -/* 0x36 */ {}, +/* 0x35 */ {dxgkio_submit_signal_to_hwqueue, + LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE}, +/* 0x36 */ {dxgkio_submit_wait_to_hwqueue, + LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE}, /* 0x37 */ {}, /* 0x38 */ {}, /* 0x39 */ {}, @@ -2999,7 +3545,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x3d */ {}, /* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3}, /* 0x3f */ {dxgkio_share_objects, LX_DXSHAREOBJECTS}, -/* 0x40 */ {}, +/* 0x40 */ {dxgkio_open_sync_object_nt, LX_DXOPENSYNCOBJECTFROMNTHANDLE2}, /* 0x41 */ {dxgkio_query_resource_info_nt, LX_DXQUERYRESOURCEINFOFROMNTHANDLE}, /* 0x42 */ {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index f74564cf7ee9..a78252901c8d 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -201,6 +201,16 @@ struct d3dkmt_createcontextvirtual { struct d3dkmthandle context; }; =20 +struct d3dddi_createhwqueueflags { + union { + struct { + __u32 disable_gpu_timeout:1; + __u32 reserved:31; + }; + __u32 value; + }; +}; + enum d3dkmdt_gdisurfacetype { _D3DKMDT_GDISURFACE_INVALID =3D 0, _D3DKMDT_GDISURFACE_TEXTURE =3D 1, @@ -694,6 +704,81 @@ struct d3dddi_openallocationinfo2 { __u64 reserved[6]; }; =20 +struct d3dkmt_createhwqueue { + struct d3dkmthandle context; + struct d3dddi_createhwqueueflags flags; + __u32 priv_drv_data_size; + __u32 reserved; +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + struct d3dkmthandle queue; + struct d3dkmthandle queue_progress_fence; +#ifdef __KERNEL__ + void *queue_progress_fence_cpu_va; +#else + __u64 queue_progress_fence_cpu_va; +#endif + __u64 queue_progress_fence_gpu_va; +}; + +struct d3dkmt_destroyhwqueue { + struct d3dkmthandle queue; +}; + +struct d3dkmt_submitwaitforsyncobjectstohwqueue { + struct d3dkmthandle hwqueue; + __u32 object_count; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; + __u64 *fence_values; +#else + __u64 objects; + __u64 fence_values; +#endif +}; + +struct d3dkmt_submitsignalsyncobjectstohwqueue { + struct d3dddicb_signalflags flags; + __u32 hwqueue_count; +#ifdef __KERNEL__ + struct d3dkmthandle *hwqueues; +#else + __u64 hwqueues; +#endif + __u32 object_count; + __u32 reserved; +#ifdef __KERNEL__ + struct d3dkmthandle *objects; + __u64 *fence_values; +#else + __u64 objects; + __u64 fence_values; +#endif +}; + +struct d3dkmt_opensyncobjectfromnthandle2 { + __u64 nt_handle; + struct d3dkmthandle device; + struct d3dddi_synchronizationobject_flags flags; + struct d3dkmthandle sync_object; + __u32 reserved1; + union { + struct { +#ifdef __KERNEL__ + void *fence_value_cpu_va; +#else + __u64 fence_value_cpu_va; +#endif + __u64 fence_value_gpu_va; + __u32 engine_affinity; + } monitored_fence; + __u64 reserved[8]; + }; +}; + struct d3dkmt_openresourcefromnthandle { struct d3dkmthandle device; __u32 reserved; @@ -819,6 +904,10 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x14, struct d3dkmt_enumadapters2) #define LX_DXCLOSEADAPTER \ _IOWR(0x47, 0x15, struct d3dkmt_closeadapter) +#define LX_DXCREATEHWQUEUE \ + _IOWR(0x47, 0x18, struct d3dkmt_createhwqueue) +#define LX_DXDESTROYHWQUEUE \ + _IOWR(0x47, 0x1b, struct d3dkmt_destroyhwqueue) #define LX_DXDESTROYDEVICE \ _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) #define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ @@ -829,6 +918,10 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x32, struct d3dkmt_signalsynchronizationobjectfromgpu) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2 \ _IOWR(0x47, 0x33, struct d3dkmt_signalsynchronizationobjectfromgpu2) +#define LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE \ + _IOWR(0x47, 0x35, struct d3dkmt_submitsignalsyncobjectstohwqueue) +#define LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE \ + _IOWR(0x47, 0x36, struct d3dkmt_submitwaitforsyncobjectstohwqueue) #define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x3a, struct d3dkmt_waitforsynchronizationobjectfromcpu) #define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7F213F99F7 for ; Thu, 19 Mar 2026 20:25:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951934; cv=none; b=EfdAjd3RLpAqLgE+m/3W4WmeoGRtFoS23kGbHxpmvXEHIInscUNAvjL+0qlpJkdY+bbtlPnSfJvOj7c4CDQdgYtBnVf2ChswL4SgjGmTyWj+qF7WGn/rF0dqGgakEfrF2aOhXNK3YqTaMxkFjbPCKidyasspySqBKoQmCDOjGGg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951934; c=relaxed/simple; bh=Wyfl5HMleWSVQS2+JE3lSyv2/KjGm8u0uivL3jjSyy0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Hb+dD4eO088CfcyN0nbrQOls1D0Lwd9O/2Q5i480OPx1YExvHUSo68nil+YVITgP1qkKv/xLSpiusqHr0I9TAje2wW6motHjIk9jjLT4MczP4vDqi1BIZlkDI6sdF6veBktvDNPvvgTUa+4ss0fRkRPanjhC8VGrLiHTxssZUMI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=F9wRChrF; arc=none smtp.client-ip=209.85.221.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="F9wRChrF" Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-43b4121c40aso903695f8f.0 for ; Thu, 19 Mar 2026 13:25:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951929; x=1774556729; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=foecVG4NkSz3e2l7RzQJubwhPdT7oC4jV/7FgDEFmFs=; b=F9wRChrFjr//TotHPtk2na3IA68XdhGu8F/XMwJRFxq8pIYK2dge34b70GP1To5yaD j8Z9BpQKIZZiFEqp/8//l8OKzyaB+Y46ebxeLyQYtsPocaq+2CHfQLhNTrW0fMbellKC AFoxdoxYmM7jjJ4r7YpaV/+5NBYSgeq+cmHfSRT3jIeUO9nvEbxMgtP9oLBjgtRD3iSk Yhsl7+DCTyyvt90aRZ5bOsxNUTm1woXQfHSKlV9MRKhbuUg4VVZwD5ZEcLL8DxqbIDvw D9CGe149qpZzvnyUD1wnE7MP2Ytk/IRVHCaDn7QRDfr3fbyj0anh1s/OK0buTicd1Vcq cjVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951929; x=1774556729; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=foecVG4NkSz3e2l7RzQJubwhPdT7oC4jV/7FgDEFmFs=; b=Q7afjBnws30N1OHRrg3VK26O8PgL3HYKrfU5HBVKHzTb7P5zdXG+BVFA9corS8SXbR 39Ln/0nQ0DLd57tz5bJ+Qj22eiNTnA2gp4jI2ayyvC66Cl0QmBlTdQzR+AS8FUfQmvZE pzgBXiSjiHRZVveYHzaOJANAGV01UPIffMMuZdbNj4VCdBYKOznqqCrLB0LDIvzitxhc 9RORzoJNtcBKsEWcZa0YFjavVrtYFLgKpHZlCMh4oDArTXKWfpec/OHOD3DaPQyYAfIP TNATOz5HeYVWW3/s2lJAhMKhv/dGka4VAkEej9o1BVQisTpipgSDDw8spAKQc3KeDCg6 UHBQ== X-Gm-Message-State: AOJu0YxqW/D42RuAwZhQ1cK4VYgjFGERePdnC/DDPH0lLYTWRX7+rsN9 +KFNuMVrQK1LMI+24hnBmD5KkDXCZiPQX4D+fqpxeRyzSmI8Gg1qqSvK X-Gm-Gg: ATEYQzyoegGeXWC8tUSvHxHbEjuAjN8vkubo0erQFwBAKJGkuSrpIGUscss74o3lziI 3bR1msNfDuJ5zd8/+wc/NGr8SxXiMO5aPqGk4OnywORytJ9CBM4CecA1t6dywTwTk9xjhs3vc9p K1/eqVlrmRPufzdLz47owBWEQ4y2fr4BVeDJJ5xuMc5o+9J0uXUFMdpgJxQoP7tQRLzW5UZjYij nlRiGAnOHG/hkF1iScGrjxCXL7I9Q7cabcQb7mayEVFvGJ6rdVyoVPekssf60sshJa82PU8bf18 svCekTFUPq4nmF752zYWd0dbLeqFarvw6dHYBr+iGVaU3uQ5UFzG3ReNkYj3f2+FUpTIGCoyS2k eLbItHW8ZA1zbqfE3A3WxJE06HwRQ7xjSxOcVLPMRHUtWNnSuy7HT3thjBMyvvZw0PegGTjKUKD fn97iJJgj4Dj7P01X5UjFJJLzHNG6x4GRzYISp12nepkW2k6wvrvXyJ4WN9ps= X-Received: by 2002:a5d:584b:0:b0:43b:54c9:7d21 with SMTP id ffacd0b85a97d-43b642816c1mr1148905f8f.37.1773951928897; Thu, 19 Mar 2026 13:25:28 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.27 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:28 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 13/55] drivers: hv: dxgkrnl: Creation of paging queue objects. Date: Thu, 19 Mar 2026 20:24:27 +0000 Message-ID: <20260319202509.63802-14-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls for creation/destruction of the paging queue objects: - LX_DXCREATEPAGINGQUEUE, - LX_DXDESTROYPAGINGQUEUE Paging queue objects (dxgpagingqueue) contain operations, which handle residency of device accessible allocations. An allocation is resident, when the device has access to it. For example, the allocation resides in local device memory or device page tables point to system memory which is made non-pageable. Each paging queue has an associated monitored fence sync object, which is used to detect when a paging operation is completed. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 89 +++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 24 ++++ drivers/hv/dxgkrnl/dxgprocess.c | 4 + drivers/hv/dxgkrnl/dxgvmbus.c | 74 +++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 17 +++ drivers/hv/dxgkrnl/ioctl.c | 189 +++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 27 +++++ 7 files changed, 418 insertions(+), 6 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index f59173f13559..410f08768bad 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -278,6 +278,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *a= dapter, void dxgdevice_stop(struct dxgdevice *device) { struct dxgallocation *alloc; + struct dxgpagingqueue *pqueue; struct dxgsyncobject *syncobj; =20 DXG_TRACE("Stopping device: %p", device); @@ -288,6 +289,10 @@ void dxgdevice_stop(struct dxgdevice *device) dxgdevice_release_alloc_list_lock(device); =20 hmgrtable_lock(&device->process->handle_table, DXGLOCK_EXCL); + list_for_each_entry(pqueue, &device->pqueue_list_head, + pqueue_list_entry) { + dxgpagingqueue_stop(pqueue); + } list_for_each_entry(syncobj, &device->syncobj_list_head, syncobj_list_entry) { dxgsyncobject_stop(syncobj); @@ -375,6 +380,17 @@ void dxgdevice_destroy(struct dxgdevice *device) dxgdevice_release_context_list_lock(device); } =20 + { + struct dxgpagingqueue *tmp; + struct dxgpagingqueue *pqueue; + + DXG_TRACE("destroying paging queues"); + list_for_each_entry_safe(pqueue, tmp, &device->pqueue_list_head, + pqueue_list_entry) { + dxgpagingqueue_destroy(pqueue); + } + } + /* Guest handles need to be released before the host handles */ hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); if (device->handle_valid) { @@ -708,6 +724,26 @@ void dxgdevice_release(struct kref *refcount) kfree(device); } =20 +void dxgdevice_add_paging_queue(struct dxgdevice *device, + struct dxgpagingqueue *entry) +{ + dxgdevice_acquire_alloc_list_lock(device); + list_add_tail(&entry->pqueue_list_entry, &device->pqueue_list_head); + dxgdevice_release_alloc_list_lock(device); +} + +void dxgdevice_remove_paging_queue(struct dxgpagingqueue *pqueue) +{ + struct dxgdevice *device =3D pqueue->device; + + dxgdevice_acquire_alloc_list_lock(device); + if (pqueue->pqueue_list_entry.next) { + list_del(&pqueue->pqueue_list_entry); + pqueue->pqueue_list_entry.next =3D NULL; + } + dxgdevice_release_alloc_list_lock(device); +} + void dxgdevice_add_syncobj(struct dxgdevice *device, struct dxgsyncobject *syncobj) { @@ -899,6 +935,59 @@ else kfree(alloc); } =20 +struct dxgpagingqueue *dxgpagingqueue_create(struct dxgdevice *device) +{ + struct dxgpagingqueue *pqueue; + + pqueue =3D kzalloc(sizeof(*pqueue), GFP_KERNEL); + if (pqueue) { + pqueue->device =3D device; + pqueue->process =3D device->process; + pqueue->device_handle =3D device->handle; + dxgdevice_add_paging_queue(device, pqueue); + } + return pqueue; +} + +void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue) +{ + int ret; + + if (pqueue->mapped_address) { + ret =3D dxg_unmap_iospace(pqueue->mapped_address, PAGE_SIZE); + DXG_TRACE("fence is unmapped %d %p", + ret, pqueue->mapped_address); + pqueue->mapped_address =3D NULL; + } +} + +void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue) +{ + struct dxgprocess *process =3D pqueue->process; + + DXG_TRACE("Destroying pqueue %p %x", pqueue, pqueue->handle.v); + + dxgpagingqueue_stop(pqueue); + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + if (pqueue->handle.v) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + pqueue->handle); + pqueue->handle.v =3D 0; + } + if (pqueue->syncobj_handle.v) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_MONITOREDFENCE, + pqueue->syncobj_handle); + pqueue->syncobj_handle.v =3D 0; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + if (pqueue->device) + dxgdevice_remove_paging_queue(pqueue); + kfree(pqueue); +} + struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *pr= ocess, struct dxgadapter *adapter) { diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 0330352b9c06..440d1f9b8882 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -104,6 +104,16 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, s= truct hv_device *hdev); void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch); void dxgvmbuschannel_receive(void *ctx); =20 +struct dxgpagingqueue { + struct dxgdevice *device; + struct dxgprocess *process; + struct list_head pqueue_list_entry; + struct d3dkmthandle device_handle; + struct d3dkmthandle handle; + struct d3dkmthandle syncobj_handle; + void *mapped_address; +}; + /* * The structure describes an event, which will be signaled by * a message from host. @@ -127,6 +137,10 @@ struct dxghosteventcpu { bool remove_from_list; }; =20 +struct dxgpagingqueue *dxgpagingqueue_create(struct dxgdevice *device); +void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue); +void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue); + /* * This is GPU synchronization object, which is used to synchronize execut= ion * between GPU contextx/hardware queues or for tracking GPU execution prog= ress. @@ -516,6 +530,9 @@ void dxgdevice_remove_alloc_safe(struct dxgdevice *dev, struct dxgallocation *a); void dxgdevice_add_resource(struct dxgdevice *dev, struct dxgresource *res= ); void dxgdevice_remove_resource(struct dxgdevice *dev, struct dxgresource *= res); +void dxgdevice_add_paging_queue(struct dxgdevice *dev, + struct dxgpagingqueue *pqueue); +void dxgdevice_remove_paging_queue(struct dxgpagingqueue *pqueue); void dxgdevice_add_syncobj(struct dxgdevice *dev, struct dxgsyncobject *so= ); void dxgdevice_remove_syncobj(struct dxgsyncobject *so); bool dxgdevice_is_active(struct dxgdevice *dev); @@ -762,6 +779,13 @@ dxgvmb_send_create_context(struct dxgadapter *adapter, int dxgvmb_send_destroy_context(struct dxgadapter *adapter, struct dxgprocess *process, struct d3dkmthandle h); +int dxgvmb_send_create_paging_queue(struct dxgprocess *pr, + struct dxgdevice *dev, + struct d3dkmt_createpagingqueue *args, + struct dxgpagingqueue *pq); +int dxgvmb_send_destroy_paging_queue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle h); int dxgvmb_send_create_allocation(struct dxgprocess *pr, struct dxgdevice = *dev, struct d3dkmt_createallocation *args, struct d3dkmt_createallocation *__user inargs, diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.c index 4021084ebd78..5de3f8ccb448 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -277,6 +277,10 @@ struct dxgdevice *dxgprocess_device_by_object_handle(s= truct dxgprocess *process, device_handle =3D ((struct dxgcontext *)obj)->device_handle; break; + case HMGRENTRY_TYPE_DXGPAGINGQUEUE: + device_handle =3D + ((struct dxgpagingqueue *)obj)->device_handle; + break; case HMGRENTRY_TYPE_DXGHWQUEUE: device_handle =3D ((struct dxghwqueue *)obj)->device_handle; diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index e83600945de1..c9c00b288ae0 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1155,6 +1155,80 @@ int dxgvmb_send_destroy_context(struct dxgadapter *a= dapter, return ret; } =20 +int dxgvmb_send_create_paging_queue(struct dxgprocess *process, + struct dxgdevice *device, + struct d3dkmt_createpagingqueue *args, + struct dxgpagingqueue *pqueue) +{ + struct dxgkvmb_command_createpagingqueue_return result; + struct dxgkvmb_command_createpagingqueue *command; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, device->adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_CREATEPAGINGQUEUE, + process->host_handle); + command->args =3D *args; + args->paging_queue.v =3D 0; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result, + sizeof(result)); + if (ret < 0) { + DXG_ERR("send_create_paging_queue failed %x", ret); + goto cleanup; + } + + args->paging_queue =3D result.paging_queue; + args->sync_object =3D result.sync_object; + args->fence_cpu_virtual_address =3D + dxg_map_iospace(result.fence_storage_physical_address, PAGE_SIZE, + PROT_READ | PROT_WRITE, true); + if (args->fence_cpu_virtual_address =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + pqueue->mapped_address =3D args->fence_cpu_virtual_address; + pqueue->handle =3D args->paging_queue; + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_destroy_paging_queue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle h) +{ + int ret; + struct dxgkvmb_command_destroypagingqueue *command; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_DESTROYPAGINGQUEUE, + process->host_handle); + command->paging_queue =3D h; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, NULL, 0); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + static int copy_private_data(struct d3dkmt_createallocation *args, struct dxgkvmb_command_createallocation *command, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 2e2fd1ae5ec2..aba075d374c9 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -462,6 +462,23 @@ struct dxgkvmb_command_destroycontext { struct d3dkmthandle context; }; =20 +struct dxgkvmb_command_createpagingqueue { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_createpagingqueue args; +}; + +struct dxgkvmb_command_createpagingqueue_return { + struct d3dkmthandle paging_queue; + struct d3dkmthandle sync_object; + u64 fence_storage_physical_address; + u64 fence_storage_offset; +}; + +struct dxgkvmb_command_destroypagingqueue { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle paging_queue; +}; + struct dxgkvmb_command_createsyncobject { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmt_createsynchronizationobject2 args; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 3cfc1c40e0bb..a2d236f5eff5 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -329,7 +329,7 @@ static int dxgsharedresource_seal(struct dxgsharedresou= rce *shared_resource) =20 if (alloc_data_size) { if (data_size < alloc_data_size) { - dev_err(DXGDEV, + DXG_ERR( "Invalid private data size"); ret =3D -EINVAL; goto cleanup1; @@ -1010,6 +1010,183 @@ static int dxgkio_destroy_hwqueue(struct dxgprocess= *process, return ret; } =20 +static int +dxgkio_create_paging_queue(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_createpagingqueue args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct dxgpagingqueue *pqueue =3D NULL; + int ret; + struct d3dkmthandle host_handle =3D {}; + bool device_lock_acquired =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) + goto cleanup; + + device_lock_acquired =3D true; + adapter =3D device->adapter; + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + pqueue =3D dxgpagingqueue_create(device); + if (pqueue =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + ret =3D dxgvmb_send_create_paging_queue(process, device, &args, pqueue); + if (ret >=3D 0) { + host_handle =3D args.paging_queue; + + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(&process->handle_table, pqueue, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + host_handle); + if (ret >=3D 0) { + pqueue->handle =3D host_handle; + ret =3D hmgrtable_assign_handle(&process->handle_table, + NULL, + HMGRENTRY_TYPE_MONITOREDFENCE, + args.sync_object); + if (ret >=3D 0) + pqueue->syncobj_handle =3D args.sync_object; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + /* should not fail after this */ + } + +cleanup: + + if (ret < 0) { + if (pqueue) + dxgpagingqueue_destroy(pqueue); + if (host_handle.v) + dxgvmb_send_destroy_paging_queue(process, + adapter, + host_handle); + } + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) { + if (device_lock_acquired) + dxgdevice_release_lock_shared(device); + kref_put(&device->device_kref, dxgdevice_release); + } + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_destroy_paging_queue(struct dxgprocess *process, void *__user inarg= s) +{ + struct d3dddi_destroypagingqueue args; + struct dxgpagingqueue *paging_queue =3D NULL; + int ret; + struct d3dkmthandle device_handle =3D {}; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + paging_queue =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + args.paging_queue); + if (paging_queue) { + device_handle =3D paging_queue->device_handle; + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + args.paging_queue); + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_MONITOREDFENCE, + paging_queue->syncobj_handle); + paging_queue->syncobj_handle.v =3D 0; + paging_queue->handle.v =3D 0; + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + if (device_handle.v) + device =3D dxgprocess_device_by_handle(process, device_handle); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_destroy_paging_queue(process, adapter, + args.paging_queue); + + dxgpagingqueue_destroy(paging_queue); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) { + dxgdevice_release_lock_shared(device); + kref_put(&device->device_kref, dxgdevice_release); + } + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int get_standard_alloc_priv_data(struct dxgdevice *device, struct d3dkmt_createstandardallocation *alloc_info, @@ -1272,7 +1449,7 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) args.private_runtime_resource_handle; if (args.flags.create_shared) { if (!args.flags.nt_security_sharing) { - dev_err(DXGDEV, + DXG_ERR( "nt_security_sharing must be set"); ret =3D -EINVAL; goto cleanup; @@ -1313,7 +1490,7 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) args.private_runtime_data, args.private_runtime_data_size); if (ret) { - dev_err(DXGDEV, + DXG_ERR( "failed to copy runtime data"); ret =3D -EINVAL; goto cleanup; @@ -1333,7 +1510,7 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) args.priv_drv_data, args.priv_drv_data_size); if (ret) { - dev_err(DXGDEV, + DXG_ERR( "failed to copy res data"); ret =3D -EINVAL; goto cleanup; @@ -3481,7 +3658,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x04 */ {dxgkio_create_context_virtual, LX_DXCREATECONTEXTVIRTUAL}, /* 0x05 */ {dxgkio_destroy_context, LX_DXDESTROYCONTEXT}, /* 0x06 */ {dxgkio_create_allocation, LX_DXCREATEALLOCATION}, -/* 0x07 */ {}, +/* 0x07 */ {dxgkio_create_paging_queue, LX_DXCREATEPAGINGQUEUE}, /* 0x08 */ {}, /* 0x09 */ {dxgkio_query_adapter_info, LX_DXQUERYADAPTERINFO}, /* 0x0a */ {}, @@ -3502,7 +3679,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x19 */ {dxgkio_destroy_device, LX_DXDESTROYDEVICE}, /* 0x1a */ {}, /* 0x1b */ {dxgkio_destroy_hwqueue, LX_DXDESTROYHWQUEUE}, -/* 0x1c */ {}, +/* 0x1c */ {dxgkio_destroy_paging_queue, LX_DXDESTROYPAGINGQUEUE}, /* 0x1d */ {dxgkio_destroy_sync_object, LX_DXDESTROYSYNCHRONIZATIONOBJECT}, /* 0x1e */ {}, /* 0x1f */ {}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index a78252901c8d..6ec70852de6e 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -211,6 +211,29 @@ struct d3dddi_createhwqueueflags { }; }; =20 +enum d3dddi_pagingqueue_priority { + _D3DDDI_PAGINGQUEUE_PRIORITY_BELOW_NORMAL =3D -1, + _D3DDDI_PAGINGQUEUE_PRIORITY_NORMAL =3D 0, + _D3DDDI_PAGINGQUEUE_PRIORITY_ABOVE_NORMAL =3D 1, +}; + +struct d3dkmt_createpagingqueue { + struct d3dkmthandle device; + enum d3dddi_pagingqueue_priority priority; + struct d3dkmthandle paging_queue; + struct d3dkmthandle sync_object; +#ifdef __KERNEL__ + void *fence_cpu_virtual_address; +#else + __u64 fence_cpu_virtual_address; +#endif + __u32 physical_adapter_index; +}; + +struct d3dddi_destroypagingqueue { + struct d3dkmthandle paging_queue; +}; + enum d3dkmdt_gdisurfacetype { _D3DKMDT_GDISURFACE_INVALID =3D 0, _D3DKMDT_GDISURFACE_TEXTURE =3D 1, @@ -890,6 +913,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x05, struct d3dkmt_destroycontext) #define LX_DXCREATEALLOCATION \ _IOWR(0x47, 0x06, struct d3dkmt_createallocation) +#define LX_DXCREATEPAGINGQUEUE \ + _IOWR(0x47, 0x07, struct d3dkmt_createpagingqueue) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) #define LX_DXCREATESYNCHRONIZATIONOBJECT \ @@ -908,6 +933,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x18, struct d3dkmt_createhwqueue) #define LX_DXDESTROYHWQUEUE \ _IOWR(0x47, 0x1b, struct d3dkmt_destroyhwqueue) +#define LX_DXDESTROYPAGINGQUEUE \ + _IOWR(0x47, 0x1c, struct d3dddi_destroypagingqueue) #define LX_DXDESTROYDEVICE \ _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) #define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 215CC3F9F27 for ; Thu, 19 Mar 2026 20:25:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951936; cv=none; b=kTz445KnXucFtQ0gtCS8JBOGCUmHk3V/lUdWHL2LCJeAGSZ5xUJ78G2I6hx9seqKGLqNZ6I2gsGWPFjKM9Tc6O38lpc070PTobB+u3c6jtvUWMTp2AyG0jNSel67Oex0T/qMpaI0mMYee/Biv8CZC7ygGdc0pEGeEq/Z7fBMtAQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951936; c=relaxed/simple; bh=TMxyYWgJby8NjV+ACi3/fTP8NXqHjx5+hMYaldGQVB4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=d5vChR2lVk/M4njjubRO1abfLPbz/X8q1D+BHknKeUd6X6cnfDKWq9FVQHIWtbCy/DTdDvcBjpXJLPgm0qYqRDXxyjH4Pn0iM04VZZJgkUAle0jRhxS+urira4R63gkrSosfL9vkIHZbNNn/3UOcK1KzW4PizZpq1Q81TDeUXX0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mjJlVyHo; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mjJlVyHo" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-439d8df7620so784460f8f.0 for ; Thu, 19 Mar 2026 13:25:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951930; x=1774556730; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4JDaklel034pI9Ckf4R38N/JQ5KooPNwXq3IvAAseYE=; b=mjJlVyHo7q6ogQFhGLW+051Y3SH33mEAEmCPUNJ/yO84B6Jo0FJFg9Axh4C48bODis Yp0Lk8bTxANfm1K3gC5yv2cKLkSuUkue82LvjgkjMCAI5CwOah4v3vUJU/0QG1JeEPhd tLuERuqSZXVefdgoWnUO5GlX12ySGP7tyvgUCcXxO64YjO8o2/C0UekBnDXq31rpPvbm h5wy+aIPWIPHz6Xq8ogGYGxlFj3B8dXkd8+cCa4m9Yt+ElIG5tbqJ6ubpZu6FQVsvZTf WCagpphjPJ9LWrYJRRCMpUAMW+jNe7C35P4KsHmwRIbgNUajeJ6xAFzXmIaH+4/dsg1U RD6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951930; x=1774556730; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=4JDaklel034pI9Ckf4R38N/JQ5KooPNwXq3IvAAseYE=; b=qls0Bav0kbvnDMor915FMTrWhq7co9KUcP+lj8HTaTIzRHQgbrtcAiqJH0AsTT8xUM RtQ9a96s7zgmYbDZZ0Dx+GRYbFqZR+sYBNY3PdJtYgFm5Zc6BOrTq7lysrt0Wh0F5LZk Ftkvb2xeWjgUR4AhZ5ytnM8X8PVkEqWpEXP2zHNsL4ngdwn6mw35Zujfyu6AKqfXYEbe 2dJR9IXOWuDckHRg/R31GgtZm7phO+H1RWk4dgV4qrE1rfmgbnHzYkCv2AVjZV4oHfaa KR16V43a4lmkhShT8dnL9JYwpZwZIPOD0WHpZctKfwfTBbW7IxoR+ReaOtNt3gfykGDu EiUg== X-Gm-Message-State: AOJu0YxutI4LnIg1BVYtVWmtAJMRXv/+wTDmYpyr5gPjHAkMGYNKuHSF TAXBa/h/ATI+1YyS0rIEf/G/YQiCUGj5X0Zqd66/1cmjTApgo/ljUmY9REXoa1RMzzA= X-Gm-Gg: ATEYQzzQDTIJkl3pJrL4O+WmmpOVqYgtLq7b39LJ+GjEKud+sp4lK0W6E251/WUVSxj +UFSKMIm7LzrMpU2PiGWbkZAwnaSP31U24NsfIkFzBa2wi9tAEYDD6X04uAhq8cuIK05dcfDAPQ g3eHcNftszc+u7JKu6x4a85crN6Ppx/9fGKpuOL4DTjmAs0+T/2415Km1OkG4S4WfPah6+Thlzo Mk9kIi0lKh2JFwb+C1ZW051egt4ndKnm+oO4ktHiHYKcECqbozEL3Ub+yCZ95s11MiHc4eiR5dl rxV+nGWEyeTc/QkF2ur0M07K2xgWN2QAHsf1ZWQlre8XiMfew/4BwDyDvULZBZdCyGfOqudqbru XGIysSLIf/x/Z5nGqi6U+wRXqKsjlyq1YnHlawyBpGak+5GHDOVISzwjOktY15TUDBGPL2zsz2h C9fIJ+QzgJjZcM2xzCKiZHRralh/nOfDtYRSLlmooevXCL/14r X-Received: by 2002:a05:6000:40c7:b0:439:bcc2:bf0a with SMTP id ffacd0b85a97d-43b6424f867mr1132863f8f.23.1773951930328; Thu, 19 Mar 2026 13:25:30 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.29 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:29 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 14/55] drivers: hv: dxgkrnl: Submit execution commands to the compute device Date: Thu, 19 Mar 2026 20:24:28 +0000 Message-ID: <20260319202509.63802-15-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implements ioctls for submission of compute device buffers for execution: - LX_DXSUBMITCOMMAND The ioctl is used to submit a command buffer to the device, working in the "packet scheduling" mode. - LX_DXSUBMITCOMMANDTOHWQUEUE The ioctl is used to submit a command buffer to the device, working in the "hardware scheduling" mode. To improve performance both ioctls use asynchronous VM bus messages to communicate with the host as these are high frequency operations. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 6 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 113 ++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 14 ++++ drivers/hv/dxgkrnl/ioctl.c | 127 +++++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 58 ++++++++++++++++ 5 files changed, 316 insertions(+), 2 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 440d1f9b8882..ab97bc53b124 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -796,6 +796,9 @@ 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_submit_command(struct dxgprocess *pr, + struct dxgadapter *adapter, + struct d3dkmt_submitcommand *args); int dxgvmb_send_create_sync_object(struct dxgprocess *pr, struct dxgadapter *adapter, struct d3dkmt_createsynchronizationobject2 @@ -838,6 +841,9 @@ int dxgvmb_send_destroy_hwqueue(struct dxgprocess *proc= ess, int dxgvmb_send_query_adapter_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryadapterinfo *args); +int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_submitcommandtohwqueue *a); int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process, struct dxgvmbuschannel *channel, struct d3dkmt_opensyncobjectfromnthandle2 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index c9c00b288ae0..7cb04fec217e 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1901,6 +1901,61 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *= device, return ret; } =20 +int dxgvmb_send_submit_command(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_submitcommand *args) +{ + int ret; + u32 cmd_size; + struct dxgkvmb_command_submitcommand *command; + u32 hbufsize =3D args->num_history_buffers * sizeof(struct d3dkmthandle); + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + struct dxgglobal *dxgglobal =3D dxggbl(); + + cmd_size =3D sizeof(struct dxgkvmb_command_submitcommand) + + hbufsize + args->priv_drv_data_size; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + ret =3D copy_from_user(&command[1], args->history_buffer_array, + hbufsize); + if (ret) { + DXG_ERR(" failed to copy history buffer"); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D 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 =3D -EINVAL; + goto cleanup; + } + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_SUBMITCOMMAND, + process->host_handle); + command->args =3D *args; + + if (dxgglobal->async_msg_enabled) { + command->hdr.async_msg =3D 1; + ret =3D dxgvmb_send_async_msg(msg.channel, msg.hdr, msg.size); + } else { + ret =3D 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) { @@ -2427,3 +2482,61 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess= *process, DXG_TRACE("err: %d", ret); return ret; } + +int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_submitcommandtohwqueue + *args) +{ + int ret =3D -EINVAL; + u32 cmd_size; + struct dxgkvmb_command_submitcommandtohwqueue *command; + u32 primaries_size =3D args->num_primaries * sizeof(struct d3dkmthandle); + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + struct dxgglobal *dxgglobal =3D dxggbl(); + + cmd_size =3D sizeof(*command) + args->priv_drv_data_size + primaries_size; + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + if (primaries_size) { + ret =3D copy_from_user(&command[1], args->written_primaries, + primaries_size); + if (ret) { + DXG_ERR("failed to copy primaries handles"); + ret =3D -EINVAL; + goto cleanup; + } + } + if (args->priv_drv_data_size) { + ret =3D copy_from_user((char *)&command[1] + primaries_size, + args->priv_drv_data, + args->priv_drv_data_size); + if (ret) { + DXG_ERR("failed to copy primaries data"); + ret =3D -EINVAL; + goto cleanup; + } + } + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_SUBMITCOMMANDTOHWQUEUE, + process->host_handle); + command->args =3D *args; + + if (dxgglobal->async_msg_enabled) { + command->hdr.async_msg =3D 1; + ret =3D dxgvmb_send_async_msg(msg.channel, msg.hdr, msg.size); + } else { + ret =3D 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; +} diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index aba075d374c9..acfdbde09e82 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -314,6 +314,20 @@ struct dxgkvmb_command_flushdevice { enum dxgdevice_flushschedulerreason reason; }; =20 +struct dxgkvmb_command_submitcommand { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_submitcommand args; + /* HistoryBufferHandles */ + /* PrivateDriverData */ +}; + +struct dxgkvmb_command_submitcommandtohwqueue { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_submitcommandtohwqueue args; + /* Written primaries */ + /* PrivateDriverData */ +}; + struct dxgkvmb_command_createallocation_allocinfo { u32 flags; u32 priv_drv_data_size; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index a2d236f5eff5..9128694c8e78 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -1902,6 +1902,129 @@ dxgkio_destroy_allocation(struct dxgprocess *proces= s, void *__user inargs) return ret; } =20 +static int +dxgkio_submit_command(struct dxgprocess *process, void *__user inargs) +{ + int ret; + struct d3dkmt_submitcommand args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.broadcast_context_count > D3DDDI_MAX_BROADCAST_CONTEXT || + args.broadcast_context_count =3D=3D 0) { + DXG_ERR("invalid number of contexts"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("invalid private data size"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.num_history_buffers > 1024) { + DXG_ERR("invalid number of history buffers"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.num_primaries > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("invalid number of primaries"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.broadcast_context[0]); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_submit_command(process, adapter, &args); + +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_submit_command_to_hwqueue(struct dxgprocess *process, void *__user = inargs) +{ + int ret; + struct d3dkmt_submitcommandtohwqueue args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("invalid private data size"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.num_primaries > DXG_MAX_VM_BUS_PACKET_SIZE) { + DXG_ERR("invalid number of primaries"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGHWQUEUE, + args.hwqueue); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_submit_command_hwqueue(process, adapter, &args); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_submit_signal_to_hwqueue(struct dxgprocess *process, void *__user i= nargs) { @@ -3666,7 +3789,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x0c */ {}, /* 0x0d */ {}, /* 0x0e */ {}, -/* 0x0f */ {}, +/* 0x0f */ {dxgkio_submit_command, LX_DXSUBMITCOMMAND}, /* 0x10 */ {dxgkio_create_sync_object, LX_DXCREATESYNCHRONIZATIONOBJECT}, /* 0x11 */ {dxgkio_signal_sync_object, LX_DXSIGNALSYNCHRONIZATIONOBJECT}, /* 0x12 */ {dxgkio_wait_sync_object, LX_DXWAITFORSYNCHRONIZATIONOBJECT}, @@ -3706,7 +3829,7 @@ static struct ioctl_desc ioctls[] =3D { LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU}, /* 0x33 */ {dxgkio_signal_sync_object_gpu2, LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2}, -/* 0x34 */ {}, +/* 0x34 */ {dxgkio_submit_command_to_hwqueue, LX_DXSUBMITCOMMANDTOHWQUEUE}, /* 0x35 */ {dxgkio_submit_signal_to_hwqueue, LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE}, /* 0x36 */ {dxgkio_submit_wait_to_hwqueue, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 6ec70852de6e..9238115d165d 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -58,6 +58,8 @@ struct winluid { __u32 b; }; =20 +#define D3DDDI_MAX_WRITTEN_PRIMARIES 16 + #define D3DKMT_CREATEALLOCATION_MAX 1024 #define D3DKMT_ADAPTERS_MAX 64 #define D3DDDI_MAX_BROADCAST_CONTEXT 64 @@ -525,6 +527,58 @@ struct d3dkmt_destroysynchronizationobject { struct d3dkmthandle sync_object; }; =20 +struct d3dkmt_submitcommandflags { + __u32 null_rendering:1; + __u32 present_redirected:1; + __u32 reserved:30; +}; + +struct d3dkmt_submitcommand { + __u64 command_buffer; + __u32 command_length; + struct d3dkmt_submitcommandflags flags; + __u64 present_history_token; + __u32 broadcast_context_count; + struct d3dkmthandle broadcast_context[D3DDDI_MAX_BROADCAST_CONTEXT]; + __u32 reserved; +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + __u32 priv_drv_data_size; + __u32 num_primaries; + struct d3dkmthandle written_primaries[D3DDDI_MAX_WRITTEN_PRIMARIES]; + __u32 num_history_buffers; + __u32 reserved1; +#ifdef __KERNEL__ + struct d3dkmthandle *history_buffer_array; +#else + __u64 history_buffer_array; +#endif +}; + +struct d3dkmt_submitcommandtohwqueue { + struct d3dkmthandle hwqueue; + __u32 reserved; + __u64 hwqueue_progress_fence_id; + __u64 command_buffer; + __u32 command_length; + __u32 priv_drv_data_size; +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + __u32 num_primaries; + __u32 reserved1; +#ifdef __KERNEL__ + struct d3dkmthandle *written_primaries; +#else + __u64 written_primaries; +#endif +}; + enum d3dkmt_standardallocationtype { _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP =3D 1, _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER =3D 2, @@ -917,6 +971,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x07, struct d3dkmt_createpagingqueue) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) +#define LX_DXSUBMITCOMMAND \ + _IOWR(0x47, 0x0f, struct d3dkmt_submitcommand) #define LX_DXCREATESYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x10, struct d3dkmt_createsynchronizationobject2) #define LX_DXSIGNALSYNCHRONIZATIONOBJECT \ @@ -945,6 +1001,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x32, struct d3dkmt_signalsynchronizationobjectfromgpu) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2 \ _IOWR(0x47, 0x33, struct d3dkmt_signalsynchronizationobjectfromgpu2) +#define LX_DXSUBMITCOMMANDTOHWQUEUE \ + _IOWR(0x47, 0x34, struct d3dkmt_submitcommandtohwqueue) #define LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE \ _IOWR(0x47, 0x35, struct d3dkmt_submitsignalsyncobjectstohwqueue) #define LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B7D03F99F3 for ; Thu, 19 Mar 2026 20:25:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951936; cv=none; b=CdURbpi4cMIaSuplqMrt1zvLSt/ttjU0f/NNVUUmbMS+GO5MXA6YXgoRnFkcl6/aKTYOBjNJTgrDcdSaAeXbraBqWBba/ASlY5phXVBdFyvoXR12RQFib+eqkH7wwqcMSkGbWgznWqVOUHftmreiZErtFqRr8RSwt6TyYobRiao= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951936; c=relaxed/simple; bh=XYXh9hWNCjjaYxIFWsgzSpcYNdUPkATphGgllc+kOiE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JFImNmiAgcMZ84hf8Ia+PkE8WrzWjY5bTEXS93nidUlGVIPNeAD3P4QNO/imQoIxkVHhLx5im4ApfWCjc22LGetXMC7t3jOUZXC9HQtJntq0qGATteabDTGThxYT4kzsO3WXtNzpbGBXTUX5OP2t6aP9mTVBfg+1JGSRNuV+D3U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=lFiZAwEV; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lFiZAwEV" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-439b611274bso598432f8f.3 for ; Thu, 19 Mar 2026 13:25:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951931; x=1774556731; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IfwWxdi0huZ+o5QErDeADcsmeHgqSR0aJcBxkGUgmUc=; b=lFiZAwEV2mQH2cRU2fS6EmzCi6rISVLe6QcO7cLDyubLtp1uaUNqR3ZuuGssjsI6vJ GyR1stFWt12C8tVR2x6V2AOkge+n/ufNtkqOb8o3AxduGD3Fzx/kTw2P+Svemfl4kn5V dDhN7tfMCpzJFc3VLcXAvhw+Li1WRFOD+l+M6Yca43DnNjbsQ8jCCXrWtuQ8ISM349/7 qTHIHBF15VxmfJdjMeAO8zW8kXUt2hhPeDVm/NDEVBvmJn73w1x3rj5ud2MdGMQcx/Nc Tse8cZrYhlpy1GAGW3Xolel6/2OjSYk4IiQU5BuW8AGTJVurCf0qOZPCafEsGcyISZGv HYlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951931; x=1774556731; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=IfwWxdi0huZ+o5QErDeADcsmeHgqSR0aJcBxkGUgmUc=; b=Wwpavc0lHOZdB83YGBHIdBsvJIIf7L63Xeb3qvROXNqirjLWRdGfMWWcIHT9w+SFAW 3yBDsixdNJg+UQmENq+Edvme0x5tgSE+1tcyKyr5nKzipYY7//4bImp8pkWMojcPGqCo moC1iJmnFQXcDpGMVDqVjTjAGom7u2H4nQuB6NJJJ4hN4FycOadgxgbQUNrcR3PzZ1ss ++TJ6l63LZFyB6tUjUlGlFhKj131QEEAa0sG4TOQWVQHYw0YzT5GDXpQEZonaTwakyO+ gsAH/7YsfFraUpI6u/PHKjoUwwGNZox6bSJ33I1FxVNdzsfn3VFzjyFulCcEFHjOcaga 1wCw== X-Gm-Message-State: AOJu0YxI61o0Paa95IVFRs+a0hX5lEMysGlAMrB/fLv1yvb0LjSsYI1m rWyJt4wmC7iIKhubi97k1QLfh1u++KrCgNqiYeVk59KhENpSQo0AvnUu X-Gm-Gg: ATEYQzx0FpI5gQzQx3tmRHU0qcLPlgGANWzKcSOJIGC57b4lGPrkX4bxJ0dsNwPczBv YMwFp1XplsO8jyfYfwwGV0amcBu8IL4jvlPmlk0A1+uL5vUaQAR/bMiJrqxgVUNw4JoEGK/Mcph gH+4Q3EFuR/Chh0sqi8ysVM5l3M7YKiC4LTHYGJBa0IPm3+/RF3lc0YIUKmyhHiIFLXaFdF+3rm sOMeJQaxM5h2YhpBnsana162HuCIypS/kzRbxwDfepU+d4rMk0zIpe0CdTxg5Y+Sh3VY4M7Hfui KeX4UeXndB/b6Ry+MPykJfmg1poMe2iNMmrItk7bTp1BGY73+/gboaFN5n+eHsOwasH1dgs1np4 KfUb0jt2pOQuTWH6cKS+oUhIy8aSjMIkAmOURMfLghUp4CU1lX/I7wgJSf7zrFMt8OYl2R03KJ+ uGMzFebuWq+CpaDUWAmc4go5kcrMz3Zuo4Ruv5fZuqsEkhMe79 X-Received: by 2002:a05:6000:2012:b0:43b:3c49:c393 with SMTP id ffacd0b85a97d-43b6424432dmr1211203f8f.18.1773951931428; Thu, 19 Mar 2026 13:25:31 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.30 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:30 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 15/55] drivers: hv: dxgkrnl: Share objects with the host Date: Thu, 19 Mar 2026 20:24:29 +0000 Message-ID: <20260319202509.63802-16-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement the LX_DXSHAREOBJECTWITHHOST ioctl. This ioctl is used to create a Windows NT handle on the host for the given shared object (resource or sync object). The NT handle is returned to the caller. The caller could share the NT handle with a host application, which needs to access the object. The host application can open the shared resource using the NT handle. This way the guest and the host have access to the same object. Fix incorrect handling of error results from copy_from_user(). Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 2 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 60 ++++++++++++++++++++++++++++++++--- drivers/hv/dxgkrnl/dxgvmbus.h | 18 +++++++++++ drivers/hv/dxgkrnl/ioctl.c | 38 ++++++++++++++++++++-- include/uapi/misc/d3dkmthk.h | 9 ++++++ 5 files changed, 120 insertions(+), 7 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index ab97bc53b124..a39d11d76e41 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -872,6 +872,8 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *dev= ice, int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel, void *command, u32 cmd_size); +int dxgvmb_send_share_object_with_host(struct dxgprocess *process, + struct d3dkmt_shareobjectwithhost *args); =20 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 7cb04fec217e..67a16de622e0 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -881,6 +881,50 @@ int dxgvmb_send_destroy_sync_object(struct dxgprocess = *process, return ret; } =20 +int dxgvmb_send_share_object_with_host(struct dxgprocess *process, + struct d3dkmt_shareobjectwithhost *args) +{ + struct dxgkvmb_command_shareobjectwithhost *command; + struct dxgkvmb_command_shareobjectwithhost_return result =3D {}; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, NULL, process, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + command_vm_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST, + process->host_handle); + command->device_handle =3D args->device_handle; + command->object_handle =3D args->object_handle; + + ret =3D dxgvmb_send_sync_msg(dxgglobal_get_dxgvmbuschannel(), + msg.hdr, msg.size, &result, sizeof(result)); + + dxgglobal_release_channel_lock(); + + if (ret || !NT_SUCCESS(result.status)) { + if (ret =3D=3D 0) + ret =3D ntstatus2int(result.status); + DXG_ERR("Host failed to share object with host: %d %x", + ret, result.status.v); + goto cleanup; + } + args->object_vail_nt_handle =3D result.vail_nt_handle; + +cleanup: + free_message(&msg, process); + if (ret) + DXG_ERR("err: %d", ret); + return ret; +} + /* * Virtual GPU messages to the host */ @@ -2323,37 +2367,43 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *p= rocess, =20 ret =3D copy_to_user(&inargs->queue, &command->hwqueue, sizeof(struct d3dkmthandle)); - if (ret < 0) { + if (ret) { DXG_ERR("failed to copy hwqueue handle"); + ret =3D -EINVAL; goto cleanup; } ret =3D copy_to_user(&inargs->queue_progress_fence, &command->hwqueue_progress_fence, sizeof(struct d3dkmthandle)); - if (ret < 0) { + if (ret) { DXG_ERR("failed to progress fence"); + ret =3D -EINVAL; goto cleanup; } ret =3D copy_to_user(&inargs->queue_progress_fence_cpu_va, &hwqueue->progress_fence_mapped_address, sizeof(inargs->queue_progress_fence_cpu_va)); - if (ret < 0) { + if (ret) { DXG_ERR("failed to copy fence cpu va"); + ret =3D -EINVAL; goto cleanup; } ret =3D copy_to_user(&inargs->queue_progress_fence_gpu_va, &command->hwqueue_progress_fence_gpuva, sizeof(u64)); - if (ret < 0) { + if (ret) { DXG_ERR("failed to copy fence gpu va"); + ret =3D -EINVAL; goto cleanup; } if (args->priv_drv_data_size) { ret =3D copy_to_user(args->priv_drv_data, command->priv_drv_data, args->priv_drv_data_size); - if (ret < 0) + if (ret) { DXG_ERR("failed to copy private data"); + ret =3D -EINVAL; + } } =20 cleanup: diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index acfdbde09e82..c1f693917d99 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -574,4 +574,22 @@ struct dxgkvmb_command_destroyhwqueue { struct d3dkmthandle hwqueue; }; =20 +struct dxgkvmb_command_shareobjectwithhost { + struct dxgkvmb_command_vm_to_host hdr; + struct d3dkmthandle device_handle; + struct d3dkmthandle object_handle; + u64 reserved; +}; + +struct dxgkvmb_command_shareobjectwithhost_return { + struct ntstatus status; + u32 alignment; + u64 vail_nt_handle; +}; + +int +dxgvmb_send_sync_msg(struct dxgvmbuschannel *channel, + void *command, u32 command_size, void *result, + u32 result_size); + #endif /* _DXGVMBUS_H */ diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 9128694c8e78..ac052836ce27 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -2460,6 +2460,7 @@ dxgkio_open_sync_object_nt(struct dxgprocess *process= , void *__user inargs) if (ret =3D=3D 0) goto success; DXG_ERR("failed to copy output args"); + ret =3D -EINVAL; =20 cleanup: =20 @@ -3364,8 +3365,10 @@ dxgkio_share_objects(struct dxgprocess *process, voi= d *__user inargs) tmp =3D (u64) object_fd; =20 ret =3D copy_to_user(args.shared_handle, &tmp, sizeof(u64)); - if (ret < 0) + if (ret) { DXG_ERR("failed to copy shared handle"); + ret =3D -EINVAL; + } =20 cleanup: if (ret < 0) { @@ -3773,6 +3776,37 @@ dxgkio_open_resource_nt(struct dxgprocess *process, return ret; } =20 +static int +dxgkio_share_object_with_host(struct dxgprocess *process, void *__user ina= rgs) +{ + struct d3dkmt_shareobjectwithhost args; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgvmb_send_share_object_with_host(process, &args); + if (ret) { + DXG_ERR("dxgvmb_send_share_object_with_host dailed"); + goto cleanup; + } + + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy data to user"); + ret =3D -EINVAL; + } + +cleanup: + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static struct ioctl_desc ioctls[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -3850,7 +3884,7 @@ static struct ioctl_desc ioctls[] =3D { LX_DXQUERYRESOURCEINFOFROMNTHANDLE}, /* 0x42 */ {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE}, /* 0x43 */ {}, -/* 0x44 */ {}, +/* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST}, /* 0x45 */ {}, }; =20 diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 9238115d165d..895861505e6e 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -952,6 +952,13 @@ struct d3dkmt_enumadapters3 { #endif }; =20 +struct d3dkmt_shareobjectwithhost { + struct d3dkmthandle device_handle; + struct d3dkmthandle object_handle; + __u64 reserved; + __u64 object_vail_nt_handle; +}; + /* * Dxgkrnl Graphics Port Driver ioctl definitions * @@ -1021,5 +1028,7 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x41, struct d3dkmt_queryresourceinfofromnthandle) #define LX_DXOPENRESOURCEFROMNTHANDLE \ _IOWR(0x47, 0x42, struct d3dkmt_openresourcefromnthandle) +#define LX_DXSHAREOBJECTWITHHOST \ + _IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost) =20 #endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 683003F9F3A for ; Thu, 19 Mar 2026 20:25:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951937; cv=none; b=vDYXpEyXOJEnr3aHglpls37M/ePLnTkGG8jXNODfRA5jMjz6ESAuZyOJ1XqhMDloMKiTZJ69Q/CpZndi3DNv78TmjSdvZZalVFVHc2djsrPftDa0cVVWtOOLjl8ryV4wcedV1xrpSJ35C/kY2nZ9NmgXRaH60rL/3c6YU8q1Bfo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951937; c=relaxed/simple; bh=W1uuEZiz/+T8ghB5Y2XB2MXA9ljGH13IJKVKFMxX2vY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jph1FYh3zF8deOmYBTp+d9vAyzhuSqGDz2Wr/RpjApjl38moWzwjOmajfdONAYhzdwP5i2dW0/Y3EEX9XBxLyHIHIzGXE6In3DaFS9IuJJC4auhVF9JrNDtPDHgk/zvcrDME5x/golixYBCFvyY0RyX9JvVxRNFTBKxqZ25tSH8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=aBJaMfT4; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="aBJaMfT4" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-4327790c4e9so776471f8f.2 for ; Thu, 19 Mar 2026 13:25:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951933; x=1774556733; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wknvwOJ0/2AENft5MRaRZPXzn2YmZTEafI5amLocXhs=; b=aBJaMfT4nvJFtyTbnLPR5Veo9VqaC0bt6e/LfQm1Glx/TKIo5wEvmd1mBY/76pRHDO jU3Kg8QxTP9Der4ICUcoFTfs65t/cIazI2roUWlrbVo1oLKahG8sArT2gRJ9By++Gu8x c28995gobZdwtK+oWyz0oQenu3J+7MVizHdcgkonFUFUiLGUpVFJXeNggXpQXP0hQJZ4 OEviEV/FH+5n0OBPILPE2oiuaM1kZWScvv/HNcw4uN1gQmKsNURlFseY41gegNlOvKpj qIzraRZb+r6tALWe6YUIAzJpCyXsGuQv+AZpsxkegtBgdEUM8CZk2Y1Gso0m8lEsUHA8 c+Lg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951933; x=1774556733; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=wknvwOJ0/2AENft5MRaRZPXzn2YmZTEafI5amLocXhs=; b=OjWACtYGLe/5eLfXsYMLY6512ChOgq2jKb34kaC7FNqu4K5zMW1cvFuStbl4afrL3i X54yeUZwVzrBACJ4OZE4yy68DKBhjIviJdLKBmBiQLods+FJ5Z6hZ8u/v5+Y83oEUgMI 5zcpn0iRL6eLYwVn8rxV2K/sIF6Iv6j+irkkxI+oP4H+AjoHYrLNjVJ1ar1X6fLAjdWx YOwpuE2wHv0Kw+WtTzSNjOOl+3V/di64k0Qc3SUL4tbg1+Ub5S/3E2zfMYG4WwhBJMBv 4Lzc+FU+9/pkGTMIXCz7JFHqS1ElgSHKu34m/0Cz1f6cqfSgjKcqceZ6jeGuV4Vyd2Ly d+jg== X-Gm-Message-State: AOJu0Yzq51o+mttuUvQhPBs2Wq190Csw8hB1toO0wQmxmOwiHpkATuNO NJ5197qeRwbCb2MBKao7F6eLU8dRctwVP/1+7NouQtKRQFK9IoY+wy6QoM4tkWIis9U= X-Gm-Gg: ATEYQzxwzRzCZHkiuLlC3knzN23+PNMlfZr2pbMRwlg0jZZxoMBqY2qJIyKlag+F3LH Tv7cY6eMadOErMoxbWQcVYt04MBsjmEl8juGkgvtRIK2jWTFxQmxv+UEPmeXrD2bDgCmqX3MB98 xJqaPlz9kJfsSHlA0in48ZShBHir/a64pw3s2qHSaSkkmQ4Wru5BzDCx2jmr8MxmrR6mEoeKnj6 8qX0ur8eKPEMoSZw5dxXkOP6q1nEWh3cRht71VYMeb5eio4JU0P82EXQCPz66NI/2R/v0f8SjZi DPFK8n0r90+fbVZHitBsMkADRpGiZyFGXe1OJsONMMkjbc3JEIsIkQPRNEL5IyJtbdMnfdzlb+q cg80Ot1gMd7kSqwr0p4ASiI/5vnnSU54VMDRUFaWGwDzo3Vd4jS4vITTzLywnt09DYcGKgyW2OH WHg2TNhoBplSjO5HdJBUCzA3yNQTqTcxCm9M5jkLZWt3IQrLHo X-Received: by 2002:a05:6000:25c7:b0:439:df25:b707 with SMTP id ffacd0b85a97d-43b6428ab94mr1149378f8f.55.1773951932532; Thu, 19 Mar 2026 13:25:32 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.31 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:32 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 16/55] drivers: hv: dxgkrnl: Query the dxgdevice state Date: Thu, 19 Mar 2026 20:24:30 +0000 Message-ID: <20260319202509.63802-17-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement the ioctl to query the dxgdevice state - LX_DXGETDEVICESTATE. The IOCTL is used to query the state of the given dxgdevice object (active, error, etc.). A call to the dxgdevice execution state could be high frequency. The following method is used to avoid sending a synchronous VM bus message to the host for every call: - When a dxgdevice is created, a pointer to dxgglobal->device_state_counter is sent to the host - Every time the device state on the host is changed, the host will send an asynchronous message to the guest (DXGK_VMBCOMMAND_SETGUESTDATA) and the guest will increment the device_state_counter value. - the dxgdevice object has execution_state_counter member, which is equal to dxgglobal->device_state_counter value at the time when LX_DXGETDEVICESTATE was last processed.. - if execution_state_counter is different from device_state_counter, the dxgk_vmbcommand_getdevicestate VM bus message is sent to the host. Otherwise, the cached value is returned to the caller. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 11 ++++ drivers/hv/dxgkrnl/dxgmodule.c | 1 - drivers/hv/dxgkrnl/dxgvmbus.c | 68 ++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 26 +++++++++ drivers/hv/dxgkrnl/ioctl.c | 66 ++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 101 +++++++++++++++++++++++++++++---- 6 files changed, 261 insertions(+), 12 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index a39d11d76e41..b131c3b43838 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -268,12 +268,18 @@ void dxgsyncobject_destroy(struct dxgprocess *process, void dxgsyncobject_stop(struct dxgsyncobject *syncobj); void dxgsyncobject_release(struct kref *refcount); =20 +/* + * device_state_counter - incremented every time the execition state of + * a DXGDEVICE is changed in the host. Used to optimize access to the + * device execution state. + */ struct dxgglobal { struct dxgdriver *drvdata; struct dxgvmbuschannel channel; struct hv_device *hdev; u32 num_adapters; u32 vmbus_ver; /* Interface version */ + atomic_t device_state_counter; struct resource *mem; u64 mmiospace_base; u64 mmiospace_size; @@ -512,6 +518,7 @@ struct dxgdevice { struct list_head syncobj_list_head; struct d3dkmthandle handle; enum d3dkmt_deviceexecution_state execution_state; + int execution_state_counter; u32 handle_valid; }; =20 @@ -849,6 +856,10 @@ int dxgvmb_send_open_sync_object_nt(struct dxgprocess = *process, struct d3dkmt_opensyncobjectfromnthandle2 *args, struct dxgsyncobject *syncobj); +int dxgvmb_send_get_device_state(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_getdevicestate *args, + struct d3dkmt_getdevicestate *__user inargs); int dxgvmb_send_create_nt_shared_object(struct dxgprocess *process, struct d3dkmthandle object, struct d3dkmthandle *shared_handle); diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 8cbe1095599f..5c364a46b65f 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -827,7 +827,6 @@ static struct dxgglobal *dxgglobal_create(void) #ifdef DEBUG dxgk_validate_ioctls(); #endif - return dxgglobal; } =20 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 67a16de622e0..ed800dc09180 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -281,6 +281,24 @@ static void command_vm_to_host_init1(struct dxgkvmb_co= mmand_vm_to_host *command, command->channel_type =3D DXGKVMB_VM_TO_HOST; } =20 +static void set_guest_data(struct dxgkvmb_command_host_to_vm *packet, + u32 packet_length) +{ + struct dxgkvmb_command_setguestdata *command =3D (void *)packet; + struct dxgglobal *dxgglobal =3D dxggbl(); + + DXG_TRACE("Setting guest data: %d %d %p %p", + command->data_type, + command->data32, + command->guest_pointer, + &dxgglobal->device_state_counter); + if (command->data_type =3D=3D SETGUESTDATA_DATATYPE_DWORD && + command->guest_pointer =3D=3D &dxgglobal->device_state_counter && + command->data32 !=3D 0) { + atomic_inc(&dxgglobal->device_state_counter); + } +} + static void signal_guest_event(struct dxgkvmb_command_host_to_vm *packet, u32 packet_length) { @@ -311,6 +329,9 @@ static void process_inband_packet(struct dxgvmbuschanne= l *channel, DXG_TRACE("global packet %d", packet->command_type); switch (packet->command_type) { + case DXGK_VMBCOMMAND_SETGUESTDATA: + set_guest_data(packet, packet_length); + break; case DXGK_VMBCOMMAND_SIGNALGUESTEVENT: case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE: signal_guest_event(packet, packet_length); @@ -1028,6 +1049,7 @@ struct d3dkmthandle dxgvmb_send_create_device(struct = dxgadapter *adapter, struct dxgkvmb_command_createdevice *command; struct dxgkvmb_command_createdevice_return result =3D { }; struct dxgvmbusmsg msg; + struct dxgglobal *dxgglobal =3D dxggbl(); =20 ret =3D init_message(&msg, adapter, process, sizeof(*command)); if (ret) @@ -1037,6 +1059,7 @@ struct d3dkmthandle dxgvmb_send_create_device(struct = dxgadapter *adapter, command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_CREATEDEVICE, process->host_handle); command->flags =3D args->flags; + command->error_code =3D &dxgglobal->device_state_counter; =20 ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result, sizeof(result)); @@ -1806,6 +1829,51 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess= *process, return ret; } =20 +int dxgvmb_send_get_device_state(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_getdevicestate *args, + struct d3dkmt_getdevicestate *__user output) +{ + int ret; + struct dxgkvmb_command_getdevicestate *command; + struct dxgkvmb_command_getdevicestate_return result =3D { }; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_GETDEVICESTATE, + process->host_handle); + command->args =3D *args; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result.status); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(output, &result.args, sizeof(result.args)); + if (ret) { + DXG_ERR("failed to copy output args"); + ret =3D -EINVAL; + } + + if (args->state_type =3D=3D _D3DKMT_DEVICESTATE_EXECUTION) + args->execution_state =3D result.args.execution_state; + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_open_resource(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmthandle device, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index c1f693917d99..6ca1068b0d4c 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -172,6 +172,22 @@ struct dxgkvmb_command_signalguestevent { bool dereference_event; }; =20 +enum set_guestdata_type { + SETGUESTDATA_DATATYPE_DWORD =3D 0, + SETGUESTDATA_DATATYPE_UINT64 =3D 1 +}; + +struct dxgkvmb_command_setguestdata { + struct dxgkvmb_command_host_to_vm hdr; + void *guest_pointer; + union { + u64 data64; + u32 data32; + }; + u32 dereference : 1; + u32 data_type : 4; +}; + struct dxgkvmb_command_opensyncobject { struct dxgkvmb_command_vm_to_host hdr; struct d3dkmthandle device; @@ -574,6 +590,16 @@ struct dxgkvmb_command_destroyhwqueue { struct d3dkmthandle hwqueue; }; =20 +struct dxgkvmb_command_getdevicestate { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_getdevicestate args; +}; + +struct dxgkvmb_command_getdevicestate_return { + struct d3dkmt_getdevicestate args; + struct ntstatus status; +}; + struct dxgkvmb_command_shareobjectwithhost { struct dxgkvmb_command_vm_to_host hdr; struct d3dkmthandle device_handle; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index ac052836ce27..26d410fd6e99 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3142,6 +3142,70 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proce= ss, void *__user inargs) return ret; } =20 +static int +dxgkio_get_device_state(struct dxgprocess *process, void *__user inargs) +{ + int ret; + struct d3dkmt_getdevicestate args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + int global_device_state_counter =3D 0; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + if (args.state_type =3D=3D _D3DKMT_DEVICESTATE_EXECUTION) { + global_device_state_counter =3D + atomic_read(&dxgglobal->device_state_counter); + if (device->execution_state_counter =3D=3D + global_device_state_counter) { + args.execution_state =3D device->execution_state; + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy args to user"); + ret =3D -EINVAL; + } + goto cleanup; + } + } + + ret =3D dxgvmb_send_get_device_state(process, adapter, &args, inargs); + + if (ret =3D=3D 0 && args.state_type =3D=3D _D3DKMT_DEVICESTATE_EXECUTION)= { + device->execution_state =3D args.execution_state; + device->execution_state_counter =3D global_device_state_counter; + } + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + if (ret < 0) + DXG_ERR("Failed to get device state %x", ret); + + return ret; +} + static int dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncobj, struct dxgprocess *process, @@ -3822,7 +3886,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x0b */ {}, /* 0x0c */ {}, /* 0x0d */ {}, -/* 0x0e */ {}, +/* 0x0e */ {dxgkio_get_device_state, LX_DXGETDEVICESTATE}, /* 0x0f */ {dxgkio_submit_command, LX_DXSUBMITCOMMAND}, /* 0x10 */ {dxgkio_create_sync_object, LX_DXCREATESYNCHRONIZATIONOBJECT}, /* 0x11 */ {dxgkio_signal_sync_object, LX_DXSIGNALSYNCHRONIZATIONOBJECT}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 895861505e6e..8a013b07e88a 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -236,6 +236,95 @@ struct d3dddi_destroypagingqueue { struct d3dkmthandle paging_queue; }; =20 +enum dxgk_render_pipeline_stage { + _DXGK_RENDER_PIPELINE_STAGE_UNKNOWN =3D 0, + _DXGK_RENDER_PIPELINE_STAGE_INPUT_ASSEMBLER =3D 1, + _DXGK_RENDER_PIPELINE_STAGE_VERTEX_SHADER =3D 2, + _DXGK_RENDER_PIPELINE_STAGE_GEOMETRY_SHADER =3D 3, + _DXGK_RENDER_PIPELINE_STAGE_STREAM_OUTPUT =3D 4, + _DXGK_RENDER_PIPELINE_STAGE_RASTERIZER =3D 5, + _DXGK_RENDER_PIPELINE_STAGE_PIXEL_SHADER =3D 6, + _DXGK_RENDER_PIPELINE_STAGE_OUTPUT_MERGER =3D 7, +}; + +enum dxgk_page_fault_flags { + _DXGK_PAGE_FAULT_WRITE =3D 0x1, + _DXGK_PAGE_FAULT_FENCE_INVALID =3D 0x2, + _DXGK_PAGE_FAULT_ADAPTER_RESET_REQUIRED =3D 0x4, + _DXGK_PAGE_FAULT_ENGINE_RESET_REQUIRED =3D 0x8, + _DXGK_PAGE_FAULT_FATAL_HARDWARE_ERROR =3D 0x10, + _DXGK_PAGE_FAULT_IOMMU =3D 0x20, + _DXGK_PAGE_FAULT_HW_CONTEXT_VALID =3D 0x40, + _DXGK_PAGE_FAULT_PROCESS_HANDLE_VALID =3D 0x80, +}; + +enum dxgk_general_error_code { + _DXGK_GENERAL_ERROR_PAGE_FAULT =3D 0, + _DXGK_GENERAL_ERROR_INVALID_INSTRUCTION =3D 1, +}; + +struct dxgk_fault_error_code { + union { + struct { + __u32 is_device_specific_code:1; + enum dxgk_general_error_code general_error_code:31; + }; + struct { + __u32 is_device_specific_code_reserved_bit:1; + __u32 device_specific_code:31; + }; + }; +}; + +struct d3dkmt_devicereset_state { + union { + struct { + __u32 desktop_switched:1; + __u32 reserved:31; + }; + __u32 value; + }; +}; + +struct d3dkmt_devicepagefault_state { + __u64 faulted_primitive_api_sequence_number; + enum dxgk_render_pipeline_stage faulted_pipeline_stage; + __u32 faulted_bind_table_entry; + enum dxgk_page_fault_flags page_fault_flags; + struct dxgk_fault_error_code fault_error_code; + __u64 faulted_virtual_address; +}; + +enum d3dkmt_deviceexecution_state { + _D3DKMT_DEVICEEXECUTION_ACTIVE =3D 1, + _D3DKMT_DEVICEEXECUTION_RESET =3D 2, + _D3DKMT_DEVICEEXECUTION_HUNG =3D 3, + _D3DKMT_DEVICEEXECUTION_STOPPED =3D 4, + _D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY =3D 5, + _D3DKMT_DEVICEEXECUTION_ERROR_DMAFAULT =3D 6, + _D3DKMT_DEVICEEXECUTION_ERROR_DMAPAGEFAULT =3D 7, +}; + +enum d3dkmt_devicestate_type { + _D3DKMT_DEVICESTATE_EXECUTION =3D 1, + _D3DKMT_DEVICESTATE_PRESENT =3D 2, + _D3DKMT_DEVICESTATE_RESET =3D 3, + _D3DKMT_DEVICESTATE_PRESENT_DWM =3D 4, + _D3DKMT_DEVICESTATE_PAGE_FAULT =3D 5, + _D3DKMT_DEVICESTATE_PRESENT_QUEUE =3D 6, +}; + +struct d3dkmt_getdevicestate { + struct d3dkmthandle device; + enum d3dkmt_devicestate_type state_type; + union { + enum d3dkmt_deviceexecution_state execution_state; + struct d3dkmt_devicereset_state reset_state; + struct d3dkmt_devicepagefault_state page_fault_state; + char alignment[48]; + }; +}; + enum d3dkmdt_gdisurfacetype { _D3DKMDT_GDISURFACE_INVALID =3D 0, _D3DKMDT_GDISURFACE_TEXTURE =3D 1, @@ -759,16 +848,6 @@ struct d3dkmt_queryadapterinfo { __u32 private_data_size; }; =20 -enum d3dkmt_deviceexecution_state { - _D3DKMT_DEVICEEXECUTION_ACTIVE =3D 1, - _D3DKMT_DEVICEEXECUTION_RESET =3D 2, - _D3DKMT_DEVICEEXECUTION_HUNG =3D 3, - _D3DKMT_DEVICEEXECUTION_STOPPED =3D 4, - _D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY =3D 5, - _D3DKMT_DEVICEEXECUTION_ERROR_DMAFAULT =3D 6, - _D3DKMT_DEVICEEXECUTION_ERROR_DMAPAGEFAULT =3D 7, -}; - struct d3dddi_openallocationinfo2 { struct d3dkmthandle allocation; #ifdef __KERNEL__ @@ -978,6 +1057,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x07, struct d3dkmt_createpagingqueue) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) +#define LX_DXGETDEVICESTATE \ + _IOWR(0x47, 0x0e, struct d3dkmt_getdevicestate) #define LX_DXSUBMITCOMMAND \ _IOWR(0x47, 0x0f, struct d3dkmt_submitcommand) #define LX_DXCREATESYNCHRONIZATIONOBJECT \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 830163F9F41 for ; Thu, 19 Mar 2026 20:25:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951939; cv=none; b=NT4xbzuK91/Je4vX+geoERqGdjHPNNgEg/zSYR+2m+OKb0QIFLunol3hpGozAZbbS/RDiT7nxmWPGhShEx2HUL34OT2yrgRp+mAlf8IA/YP5/iqmnde0fQ25nE8AhnXOJFzxQHsHMj1/JpRhevwGXV3MOX188J2S6cwrL56cMPU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951939; c=relaxed/simple; bh=Fbp9q7H4t9EaV4awmwjgI/tqECFvn+++xu/wcX174OA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iMshFMuAc69NM3qxR5rrPsshx3A6WgDY/AyMDtyeKmuAZdPp1FGHPYnh8CZbVe9wvrnW4BTn0sq6xVwORNa3OCHRQoideC4+T6bC8E3YyCWq6cdsvY/NhUiy/tr9ioz3A8QkrVV+f9ZnUKkxE66oHAh1hfOqdo3F3MekH1R7XUk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=N/3X/QHv; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="N/3X/QHv" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-48540d21f7dso14988965e9.0 for ; Thu, 19 Mar 2026 13:25:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951934; x=1774556734; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=27zyhUWeckJu0+G+QN/l2H50C9jZ20tZZMg4eAEpV4k=; b=N/3X/QHvtZERzhkN1bAD8JZDXyf+9rkGzS878xnsBxaR2dbrYCav56QIaSqthaf95c 2p7HHi2/LzFjdqJJUPkYr81oVqompp+U5eiD4FBSOAmsTMJKkTvK7KuhdgtiqdNrLckZ ow9I11L5pOIKGCd+e2bxxI100w7QGgg0gVjQHKiedcjoD3rDdfvlUZJOOX7YfpnR4tLU iRIujbOYHdskd2raFZr3sObbLJoRAv0ilOJjz7917A0SX+o5ZZRL7PoWsvmX5n8LUH9y Kdvy/sCMpkzEPdBtUNqF52NcBja2z1mHohFgyxCq/z65Ow4hNRV6t3LGssXQvbJKOUTS XL7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951934; x=1774556734; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=27zyhUWeckJu0+G+QN/l2H50C9jZ20tZZMg4eAEpV4k=; b=hgMImzTCct+tUdxW0t6hnZCZrYE2Az81QELrzTTXMh3vX0MqHr9OQmjFkV3CMb8keh Ye5aNRQ0h+pwrAM3BM8F9h9Wq+UWjMS+IAxa2w0ETYqC6rZEw12FzLuP9VgzsWQjWAsl o6IdQ2MaDSmDDscjX0XadG9UiKSwEVfPGBcE/rrk7CAY/Uu9ailI41WsFVz7XCr1KK7q FSUO1mJ3aiTZilGN8K/WLtIsI927URtku/JOj51qHlv1Bvwk81XpvBfq/ZoVo9ZjHpqZ FLfTWb7sjUITun8HHYUbP2xxbPQH7au6hLM+CVbpmayk5YniStSykgZYzuytMtN4d5yR lKGg== X-Gm-Message-State: AOJu0Yx+uCTtaGm+XrrYOTFP/LxCPvhBc4Lb4BRV2BP8p6XPbDupe6HY nvVGaRc3g9X0eM8MM+8URgb/32HXSlu4C+rl3oDi6HnPSDnJ1lEbGnHG X-Gm-Gg: ATEYQzzpUlu8oL1LVxyiZhecoJ3VsqXNpYo1OaSC6CpOAiP+eBQ8y5Dfu3/p/nfOnaK Kl9FXVXzXCL5R16RRNEfSLSEWS6CD7V4E2/hf1mXWOWA/FL2etiYjjQRAeuwmb7RjdjS2lpd6L9 sRQuG6toGo+dy0F4f+q0TtltaR45JGABGpTqBS0s7l7abfCx8OO1Kh4POw2THUHPFUu7OoeRNCS EIUJKn8i9RgjgPISHjK34N4V/hvtWQc0N/l0+8xS5jEeT5fV5eIXZsgUTzw6TRNRP84wo6j68D0 AWyrZwzGP7b9cyl0VDmVSbeLVW3xk3OuJpCWxz6NB9NCiJCRf1Y5wK/QRP0SY9x78dDh4K2q/Nv PDfUtik0r9PBMLj/QNe92NIXs06x5hpEO6IyK8INnAXnpJ8KAnxz00sAeqBD/vovAnS3fcCGYr3 Tpbr1bDXhLCH2eQoHUktYKiV7M5HIimBSfdg2UDda/Wi4OIMI7 X-Received: by 2002:a05:600c:1d15:b0:485:34b3:8587 with SMTP id 5b1f17b1804b1-486fedf9061mr6617495e9.10.1773951933549; Thu, 19 Mar 2026 13:25:33 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.32 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:33 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 17/55] drivers: hv: dxgkrnl: Map(unmap) CPU address to device allocation Date: Thu, 19 Mar 2026 20:24:31 +0000 Message-ID: <20260319202509.63802-18-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls to map/unmap CPU virtual addresses to compute device allocations - LX_DXLOCK2 and LX_DXUNLOCK2. The LX_DXLOCK2 ioctl maps a CPU virtual address to a compute device allocation. The allocation could be located in system memory or local device memory on the host. When the device allocation is created from the guest system memory (existing sysmem allocation), the allocation CPU address is known and is returned to the caller. For other CPU visible allocations the code flow is the following: 1. A VM bus message is sent to the host to map the allocation 2. The host allocates a portion of the guest IO space and maps it to the allocation backing store. The IO space address of the allocation is returned back to the guest. 3. The guest allocates a CPU virtual address and maps it to the IO space (see the dxg_map_iospace function). 4. The CPU VA is returned back to the caller cpu_address_mapped and cpu_address_refcount are used to track how many times an allocation was mapped. The LX_DXUNLOCK2 ioctl unmaps a CPU virtual address from a compute device allocation. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 11 +++ drivers/hv/dxgkrnl/dxgkrnl.h | 14 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 107 +++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 19 ++++ drivers/hv/dxgkrnl/ioctl.c | 160 +++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 30 ++++++ 6 files changed, 339 insertions(+), 2 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index 410f08768bad..23f00db7637e 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -885,6 +885,15 @@ void dxgallocation_stop(struct dxgallocation *alloc) vfree(alloc->pages); alloc->pages =3D NULL; } + dxgprocess_ht_lock_exclusive_down(alloc->process); + if (alloc->cpu_address_mapped) { + dxg_unmap_iospace(alloc->cpu_address, + alloc->num_pages << PAGE_SHIFT); + alloc->cpu_address_mapped =3D false; + alloc->cpu_address =3D NULL; + alloc->cpu_address_refcount =3D 0; + } + dxgprocess_ht_lock_exclusive_up(alloc->process); } =20 void dxgallocation_free_handle(struct dxgallocation *alloc) @@ -932,6 +941,8 @@ else #endif if (alloc->priv_drv_data) vfree(alloc->priv_drv_data); + if (alloc->cpu_address_mapped) + pr_err("Alloc IO space is mapped: %p", alloc); kfree(alloc); } =20 diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index b131c3b43838..1d6b552f1c1a 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -708,6 +708,8 @@ struct dxgallocation { struct d3dkmthandle alloc_handle; /* Set to 1 when allocation belongs to resource. */ u32 resource_owner:1; + /* Set to 1 when 'cpu_address' is mapped to the IO space. */ + u32 cpu_address_mapped:1; /* Set to 1 when the allocatio is mapped as cached */ u32 cached:1; u32 handle_valid:1; @@ -719,6 +721,11 @@ struct dxgallocation { #endif /* Number of pages in the 'pages' array */ u32 num_pages; + /* + * How many times dxgk_lock2 is called to allocation, which is mapped + * to IO space. + */ + u32 cpu_address_refcount; /* * CPU address from the existing sysmem allocation, or * mapped to the CPU visible backing store in the IO space @@ -837,6 +844,13 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgprocess= *process, d3dkmt_waitforsynchronizationobjectfromcpu *args, u64 cpu_event); +int dxgvmb_send_lock2(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_lock2 *args, + struct d3dkmt_lock2 *__user outargs); +int dxgvmb_send_unlock2(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_unlock2 *args); int dxgvmb_send_create_hwqueue(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_createhwqueue *args, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index ed800dc09180..a80f84d9065a 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -2354,6 +2354,113 @@ int dxgvmb_send_wait_sync_object_gpu(struct dxgproc= ess *process, return ret; } =20 +int dxgvmb_send_lock2(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_lock2 *args, + struct d3dkmt_lock2 *__user outargs) +{ + int ret; + struct dxgkvmb_command_lock2 *command; + struct dxgkvmb_command_lock2_return result =3D { }; + struct dxgallocation *alloc =3D NULL; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_LOCK2, process->host_handle); + command->args =3D *args; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result.status); + if (ret < 0) + goto cleanup; + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + alloc =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGALLOCATION, + args->allocation); + if (alloc =3D=3D NULL) { + DXG_ERR("invalid alloc"); + ret =3D -EINVAL; + } else { + if (alloc->cpu_address) { + args->data =3D alloc->cpu_address; + if (alloc->cpu_address_mapped) + alloc->cpu_address_refcount++; + } else { + u64 offset =3D (u64)result.cpu_visible_buffer_offset; + + args->data =3D dxg_map_iospace(offset, + alloc->num_pages << PAGE_SHIFT, + PROT_READ | PROT_WRITE, alloc->cached); + if (args->data) { + alloc->cpu_address_refcount =3D 1; + alloc->cpu_address_mapped =3D true; + alloc->cpu_address =3D args->data; + } + } + if (args->data =3D=3D NULL) { + ret =3D -ENOMEM; + } else { + ret =3D copy_to_user(&outargs->data, &args->data, + sizeof(args->data)); + if (ret) { + DXG_ERR("failed to copy data"); + ret =3D -EINVAL; + alloc->cpu_address_refcount--; + if (alloc->cpu_address_refcount =3D=3D 0) { + dxg_unmap_iospace(alloc->cpu_address, + alloc->num_pages << PAGE_SHIFT); + alloc->cpu_address_mapped =3D false; + alloc->cpu_address =3D NULL; + } + } + } + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_unlock2(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_unlock2 *args) +{ + int ret; + struct dxgkvmb_command_unlock2 *command; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_UNLOCK2, + process->host_handle); + command->args =3D *args; + + ret =3D 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_create_hwqueue(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_createhwqueue *args, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 6ca1068b0d4c..447bb1ba391b 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -570,6 +570,25 @@ struct dxgkvmb_command_waitforsyncobjectfromgpu { /* struct d3dkmthandle ObjectHandles[object_count] */ }; =20 +struct dxgkvmb_command_lock2 { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_lock2 args; + bool use_legacy_lock; + u32 flags; + u32 priv_drv_data; +}; + +struct dxgkvmb_command_lock2_return { + struct ntstatus status; + void *cpu_visible_buffer_offset; +}; + +struct dxgkvmb_command_unlock2 { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_unlock2 args; + bool use_legacy_unlock; +}; + /* Returns the same structure */ struct dxgkvmb_command_createhwqueue { struct dxgkvmb_command_vgpu_to_host hdr; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 26d410fd6e99..37e218443310 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3142,6 +3142,162 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proc= ess, void *__user inargs) return ret; } =20 +static int +dxgkio_lock2(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_lock2 args; + struct d3dkmt_lock2 *__user result =3D inargs; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxgallocation *alloc =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + args.data =3D NULL; + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + alloc =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGALLOCATION, + args.allocation); + if (alloc =3D=3D NULL) { + ret =3D -EINVAL; + } else { + if (alloc->cpu_address) { + ret =3D copy_to_user(&result->data, + &alloc->cpu_address, + sizeof(args.data)); + if (ret =3D=3D 0) { + args.data =3D alloc->cpu_address; + if (alloc->cpu_address_mapped) + alloc->cpu_address_refcount++; + } else { + DXG_ERR("Failed to copy cpu address"); + ret =3D -EINVAL; + } + } + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + if (ret < 0) + goto cleanup; + if (args.data) + goto success; + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_lock2(process, adapter, &args, result); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) + kref_put(&device->device_kref, dxgdevice_release); + +success: + DXG_TRACE("ioctl:%s %s %d", errorstr(ret), __func__, ret); + return ret; +} + +static int +dxgkio_unlock2(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_unlock2 args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxgallocation *alloc =3D NULL; + bool done =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + alloc =3D hmgrtable_get_object_by_type(&process->handle_table, + HMGRENTRY_TYPE_DXGALLOCATION, + args.allocation); + if (alloc =3D=3D NULL) { + ret =3D -EINVAL; + } else { + if (alloc->cpu_address =3D=3D NULL) { + DXG_ERR("Allocation is not locked: %p", alloc); + ret =3D -EINVAL; + } else if (alloc->cpu_address_mapped) { + if (alloc->cpu_address_refcount > 0) { + alloc->cpu_address_refcount--; + if (alloc->cpu_address_refcount !=3D 0) { + done =3D true; + } else { + dxg_unmap_iospace(alloc->cpu_address, + alloc->num_pages << PAGE_SHIFT); + alloc->cpu_address_mapped =3D false; + alloc->cpu_address =3D NULL; + } + } else { + DXG_ERR("Invalid cpu access refcount"); + done =3D true; + } + } + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + if (done) + goto success; + if (ret < 0) + goto cleanup; + + /* + * The call acquires reference on the device. It is safe to access the + * adapter, because the device holds reference on it. + */ + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_unlock2(process, adapter, &args); + +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) + kref_put(&device->device_kref, dxgdevice_release); + +success: + DXG_TRACE("ioctl:%s %s %d", errorstr(ret), __func__, ret); + return ret; +} + static int dxgkio_get_device_state(struct dxgprocess *process, void *__user inargs) { @@ -3909,7 +4065,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x22 */ {}, /* 0x23 */ {}, /* 0x24 */ {}, -/* 0x25 */ {}, +/* 0x25 */ {dxgkio_lock2, LX_DXLOCK2}, /* 0x26 */ {}, /* 0x27 */ {}, /* 0x28 */ {}, @@ -3932,7 +4088,7 @@ static struct ioctl_desc ioctls[] =3D { LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE}, /* 0x36 */ {dxgkio_submit_wait_to_hwqueue, LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE}, -/* 0x37 */ {}, +/* 0x37 */ {dxgkio_unlock2, LX_DXUNLOCK2}, /* 0x38 */ {}, /* 0x39 */ {}, /* 0x3a */ {dxgkio_wait_sync_object_cpu, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 8a013b07e88a..b498f09e694d 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -668,6 +668,32 @@ struct d3dkmt_submitcommandtohwqueue { #endif }; =20 +struct d3dddicb_lock2flags { + union { + struct { + __u32 reserved:32; + }; + __u32 value; + }; +}; + +struct d3dkmt_lock2 { + struct d3dkmthandle device; + struct d3dkmthandle allocation; + struct d3dddicb_lock2flags flags; + __u32 reserved; +#ifdef __KERNEL__ + void *data; +#else + __u64 data; +#endif +}; + +struct d3dkmt_unlock2 { + struct d3dkmthandle device; + struct d3dkmthandle allocation; +}; + enum d3dkmt_standardallocationtype { _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP =3D 1, _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER =3D 2, @@ -1083,6 +1109,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) #define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) +#define LX_DXLOCK2 \ + _IOWR(0x47, 0x25, struct d3dkmt_lock2) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x31, struct d3dkmt_signalsynchronizationobjectfromcpu) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU \ @@ -1095,6 +1123,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x35, struct d3dkmt_submitsignalsyncobjectstohwqueue) #define LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE \ _IOWR(0x47, 0x36, struct d3dkmt_submitwaitforsyncobjectstohwqueue) +#define LX_DXUNLOCK2 \ + _IOWR(0x47, 0x37, struct d3dkmt_unlock2) #define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x3a, struct d3dkmt_waitforsynchronizationobjectfromcpu) #define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF4503F9F58 for ; Thu, 19 Mar 2026 20:25:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951942; cv=none; b=En+4NU+2f8amJ32HfotHZ/7KAMmb/Mf9pQw2cDUkUhASMpWVotgenomw0rYNY0cFR516n1/5lmzrQJmO5UOfel1laypLHHuoE75Op6riB97bQDmU2+rZoVYb9ZBnhVFA5uk3OhL/V/dQUR4b2FjlpImExJTCiDTxY9aIqqBCoYo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951942; c=relaxed/simple; bh=3j1wDPqQSZdr8k5MF2F6ulqP/7AQz9mW4yJoIeHwvak=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c55UGOwgZOH19sgewMkHbyeN6IoxSM/AN5Epqn7CZQBkddQYhzImluG49p1a0u30WBxa0V8UW0LW6NNsaKf8JCoECRCa/6fWlT3B0bDGybhpBxQqeWBfs3I0khYqKP/InzHlaywDYFARAEm+RZkU2DLY/utkGjm1yOa4ZXkirb4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fQO0p6hQ; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fQO0p6hQ" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-43b4d73463dso946284f8f.3 for ; Thu, 19 Mar 2026 13:25:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951935; x=1774556735; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+ZXgxsCauWvKSz1NA+qHkAzZKiqBTe7iEdmrrC0fzSs=; b=fQO0p6hQ5wPIe4cnsobl2IPAVkwgAX7lXtRU3KB2m9FtPqRn7jFOF1De0S4eU9zFeu NJ4bCzwTFeHPxDmqgF6p2/f5Hwz/5VawxP2Zz/T4PVZTBghTUhMv4a4pZvssgE6m/aRD hfsx0Rgb3BFSvo0ziv897cDV+HE49QU4iRCwoa1wKdXY46BYc5MUtVDEAD10T14OKKtr G8L936j2XL1c1ukMKUXcJlYloTSjZcB1fDNscpx0p79uVxkbW2BLa8zlk6ORYR23aLBt nteJ2ItzqDJPyrg1z4kaBOl0lg8I5kQ2CviRb3bdPgfpgrcmlXvQQb4q0KMM+n3sEAIw oumw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951935; x=1774556735; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=+ZXgxsCauWvKSz1NA+qHkAzZKiqBTe7iEdmrrC0fzSs=; b=mZq+sXfdUzrT27lRFR7t9e/dYHtlpiXQhgDU50m21tHmeUzTf5GLa8DLxu0luASUfr v2q4Q2rX8fP++Pct80gp6cEjsP7JnQVgsvAZWUNMTp5eaWJeM8syxMv9JgfulF5Cvo06 u1vdtwA1oBUVO7YMs79SMNdS0pFUKLl5ABuDghe6WMgrk6vapuJvqJv6ensyq0HsvpVE TaGvUfxsVFGgC5xjo30bv4ShqPS+tY1pM15kmMjWU/RNijVHGZsk4i77QFZtSeZf3vBi DjRj80nGGfVIQq7czJ9XXUxbI90yWLrj2G2sxiTJmfy4Uz540E95iVvCbFEJE6EakEIF yUcA== X-Gm-Message-State: AOJu0YyVxjoqmRLNkxlp6ySjhrMW5whryABCj/CFfsu+U0nrnpsliAo0 HEoI43AY8JAzp3i9/ZghDPaXrhsNGxt+RnBqVrbIr/sd1W+5wd6eqefeIDihONQBceQ= X-Gm-Gg: ATEYQzzHhBOI01n4kcsoS5ByE3feZkh1z4wAr5rM8S5ALLHEDIj6O19HTYhfjaLvi1p DQ4PpsSvjZHC2poFyuh6UUgDL5PI7d9i0HncLg93siQudeo6I7phlr1KMMcN/Nq1niCvNG8n95m mgE3sDVN6+qtfzqd0RP4JA1CJsgg7L7J3SjQma9LQS84s399VLFXLk0RFvAnyfc7BwuuI52yp2Y mWdTjxLlGuDHPulG6RvheLtK6m4I9wSAP5VbRi55b53Z7RD+15A2pcmMIxbToHGfZetClcs8NMj gJJ4xpf7GFT6IHmdXitcfxPuv5eeTPhMyEJmefndblzRY4d6G0qxE104aryTpG8jq/ycMZ/5Dzz mYRusa6laRIzowVUQl72+NNNYYOrT7vkDniEWUJ6TUXRaqH8g6+I4IFsQyjpBHyHs2oZ9/TIktR g9LRWyMCRX59b8TQOTzF3XjMVcuQuPdNvMlktll0Zay8qoqN/M X-Received: by 2002:a05:6000:2007:b0:43b:41df:705e with SMTP id ffacd0b85a97d-43b6428aa4fmr1299751f8f.49.1773951934625; Thu, 19 Mar 2026 13:25:34 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.33 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:34 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 18/55] drivers: hv: dxgkrnl: Manage device allocation properties Date: Thu, 19 Mar 2026 20:24:32 +0000 Message-ID: <20260319202509.63802-19-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls to manage properties of a compute device allocation: - LX_DXUPDATEALLOCPROPERTY, - LX_DXSETALLOCATIONPRIORITY, - LX_DXGETALLOCATIONPRIORITY, - LX_DXQUERYALLOCATIONRESIDENCY. - LX_DXCHANGEVIDEOMEMORYRESERVATION, The LX_DXUPDATEALLOCPROPERTY ioctl requests the host to update various properties of a compute devoce allocation. The LX_DXSETALLOCATIONPRIORITY and LX_DXGETALLOCATIONPRIORITY ioctls are used to set/get allocation priority, which defines the importance of the allocation to be in the local device memory. The LX_DXQUERYALLOCATIONRESIDENCY ioctl queries if the allocation is located in the compute device accessible memory. The LX_DXCHANGEVIDEOMEMORYRESERVATION ioctl changes compute device memory reservation of an allocation. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 21 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 300 ++++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 50 ++++++ drivers/hv/dxgkrnl/ioctl.c | 217 +++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 127 ++++++++++++++ 5 files changed, 708 insertions(+), 7 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 1d6b552f1c1a..7fefe4617488 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -851,6 +851,23 @@ int dxgvmb_send_lock2(struct dxgprocess *process, int dxgvmb_send_unlock2(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_unlock2 *args); +int dxgvmb_send_update_alloc_property(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dddi_updateallocproperty *args, + struct d3dddi_updateallocproperty *__user + inargs); +int dxgvmb_send_set_allocation_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_setallocationpriority *a); +int dxgvmb_send_get_allocation_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_getallocationpriority *a); +int dxgvmb_send_change_vidmem_reservation(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle other_process, + struct + d3dkmt_changevideomemoryreservation + *args); int dxgvmb_send_create_hwqueue(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_createhwqueue *args, @@ -870,6 +887,10 @@ int dxgvmb_send_open_sync_object_nt(struct dxgprocess = *process, struct d3dkmt_opensyncobjectfromnthandle2 *args, struct dxgsyncobject *syncobj); +int dxgvmb_send_query_alloc_residency(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryallocationresidency + *args); int dxgvmb_send_get_device_state(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_getdevicestate *args, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index a80f84d9065a..dd2c97fee27b 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1829,6 +1829,79 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess= *process, return ret; } =20 +int dxgvmb_send_query_alloc_residency(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryallocationresidency + *args) +{ + int ret =3D -EINVAL; + struct dxgkvmb_command_queryallocationresidency *command =3D NULL; + u32 cmd_size =3D sizeof(*command); + u32 alloc_size =3D 0; + u32 result_allocation_size =3D 0; + struct dxgkvmb_command_queryallocationresidency_return *result =3D NULL; + u32 result_size =3D sizeof(*result); + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; + + if (args->allocation_count > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EINVAL; + goto cleanup; + } + + if (args->allocation_count) { + alloc_size =3D args->allocation_count * + sizeof(struct d3dkmthandle); + cmd_size +=3D alloc_size; + result_allocation_size =3D args->allocation_count * + sizeof(args->residency_status[0]); + } else { + result_allocation_size =3D sizeof(args->residency_status[0]); + } + result_size +=3D result_allocation_size; + + ret =3D init_message_res(&msg, adapter, process, cmd_size, result_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + result =3D msg.res; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_QUERYALLOCATIONRESIDENCY, + process->host_handle); + command->args =3D *args; + if (alloc_size) { + ret =3D copy_from_user(&command[1], args->allocations, + alloc_size); + if (ret) { + DXG_ERR("failed to copy alloc handles"); + ret =3D -EINVAL; + goto cleanup; + } + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + result, msg.res_size); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result->status); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(args->residency_status, &result[1], + result_allocation_size); + if (ret) { + DXG_ERR("failed to copy residency status"); + ret =3D -EINVAL; + } + +cleanup: + free_message((struct dxgvmbusmsg *)&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_get_device_state(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_getdevicestate *args, @@ -2461,6 +2534,233 @@ int dxgvmb_send_unlock2(struct dxgprocess *process, return ret; } =20 +int dxgvmb_send_update_alloc_property(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dddi_updateallocproperty *args, + struct d3dddi_updateallocproperty *__user + inargs) +{ + int ret; + int ret1; + struct dxgkvmb_command_updateallocationproperty *command; + struct dxgkvmb_command_updateallocationproperty_return result =3D { }; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_UPDATEALLOCATIONPROPERTY, + process->host_handle); + command->args =3D *args; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + + if (ret < 0) + goto cleanup; + ret =3D ntstatus2int(result.status); + /* STATUS_PENING is a success code > 0 */ + if (ret =3D=3D STATUS_PENDING) { + ret1 =3D copy_to_user(&inargs->paging_fence_value, + &result.paging_fence_value, + sizeof(u64)); + if (ret1) { + DXG_ERR("failed to copy paging fence"); + ret =3D -EINVAL; + } + } +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_set_allocation_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_setallocationpriority *args) +{ + u32 cmd_size =3D sizeof(struct dxgkvmb_command_setallocationpriority); + u32 alloc_size =3D 0; + u32 priority_size =3D 0; + struct dxgkvmb_command_setallocationpriority *command; + int ret; + struct d3dkmthandle *allocations; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + if (args->allocation_count > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EINVAL; + goto cleanup; + } + if (args->resource.v) { + priority_size =3D sizeof(u32); + if (args->allocation_count !=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + } else { + if (args->allocation_count =3D=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + alloc_size =3D args->allocation_count * + sizeof(struct d3dkmthandle); + cmd_size +=3D alloc_size; + priority_size =3D sizeof(u32) * args->allocation_count; + } + cmd_size +=3D priority_size; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_SETALLOCATIONPRIORITY, + process->host_handle); + command->device =3D args->device; + command->allocation_count =3D args->allocation_count; + command->resource =3D args->resource; + allocations =3D (struct d3dkmthandle *) &command[1]; + ret =3D copy_from_user(allocations, args->allocation_list, + alloc_size); + if (ret) { + DXG_ERR("failed to copy alloc handle"); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D copy_from_user((u8 *) allocations + alloc_size, + args->priorities, priority_size); + if (ret) { + DXG_ERR("failed to copy alloc priority"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D 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_get_allocation_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_getallocationpriority *args) +{ + u32 cmd_size =3D sizeof(struct dxgkvmb_command_getallocationpriority); + u32 result_size; + u32 alloc_size =3D 0; + u32 priority_size =3D 0; + struct dxgkvmb_command_getallocationpriority *command; + struct dxgkvmb_command_getallocationpriority_return *result; + int ret; + struct d3dkmthandle *allocations; + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; + + if (args->allocation_count > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EINVAL; + goto cleanup; + } + if (args->resource.v) { + priority_size =3D sizeof(u32); + if (args->allocation_count !=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + } else { + if (args->allocation_count =3D=3D 0) { + ret =3D -EINVAL; + goto cleanup; + } + alloc_size =3D args->allocation_count * + sizeof(struct d3dkmthandle); + cmd_size +=3D alloc_size; + priority_size =3D sizeof(u32) * args->allocation_count; + } + result_size =3D sizeof(*result) + priority_size; + + ret =3D init_message_res(&msg, adapter, process, cmd_size, result_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + result =3D msg.res; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_GETALLOCATIONPRIORITY, + process->host_handle); + command->device =3D args->device; + command->allocation_count =3D args->allocation_count; + command->resource =3D args->resource; + allocations =3D (struct d3dkmthandle *) &command[1]; + ret =3D copy_from_user(allocations, args->allocation_list, + alloc_size); + if (ret) { + DXG_ERR("failed to copy alloc handles"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, + msg.size + msg.res_size, + result, msg.res_size); + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result->status); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(args->priorities, + (u8 *) result + sizeof(*result), + priority_size); + if (ret) { + DXG_ERR("failed to copy priorities"); + ret =3D -EINVAL; + } + +cleanup: + free_message((struct dxgvmbusmsg *)&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + +int dxgvmb_send_change_vidmem_reservation(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle other_process, + struct + d3dkmt_changevideomemoryreservation + *args) +{ + struct dxgkvmb_command_changevideomemoryreservation *command; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_CHANGEVIDEOMEMORYRESERVATION, + process->host_handle); + command->args =3D *args; + command->args.process =3D other_process.v; + + ret =3D 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_create_hwqueue(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_createhwqueue *args, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 447bb1ba391b..dbb01b9ab066 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -308,6 +308,29 @@ struct dxgkvmb_command_queryadapterinfo_return { u8 private_data[1]; }; =20 +/* Returns ntstatus */ +struct dxgkvmb_command_setallocationpriority { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + struct d3dkmthandle resource; + u32 allocation_count; + /* struct d3dkmthandle allocations[allocation_count or 0]; */ + /* u32 priorities[allocation_count or 1]; */ +}; + +struct dxgkvmb_command_getallocationpriority { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + struct d3dkmthandle resource; + u32 allocation_count; + /* struct d3dkmthandle allocations[allocation_count or 0]; */ +}; + +struct dxgkvmb_command_getallocationpriority_return { + struct ntstatus status; + /* u32 priorities[allocation_count or 1]; */ +}; + struct dxgkvmb_command_createdevice { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmt_createdeviceflags flags; @@ -589,6 +612,22 @@ struct dxgkvmb_command_unlock2 { bool use_legacy_unlock; }; =20 +struct dxgkvmb_command_updateallocationproperty { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dddi_updateallocproperty args; +}; + +struct dxgkvmb_command_updateallocationproperty_return { + u64 paging_fence_value; + struct ntstatus status; +}; + +/* Returns ntstatus */ +struct dxgkvmb_command_changevideomemoryreservation { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_changevideomemoryreservation args; +}; + /* Returns the same structure */ struct dxgkvmb_command_createhwqueue { struct dxgkvmb_command_vgpu_to_host hdr; @@ -609,6 +648,17 @@ struct dxgkvmb_command_destroyhwqueue { struct d3dkmthandle hwqueue; }; =20 +struct dxgkvmb_command_queryallocationresidency { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_queryallocationresidency args; + /* struct d3dkmthandle allocations[0 or number of allocations] */ +}; + +struct dxgkvmb_command_queryallocationresidency_return { + struct ntstatus status; + /* d3dkmt_allocationresidencystatus[NumAllocations] */ +}; + struct dxgkvmb_command_getdevicestate { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmt_getdevicestate args; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 37e218443310..b626e2518ff2 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3214,7 +3214,7 @@ dxgkio_lock2(struct dxgprocess *process, void *__user= inargs) kref_put(&device->device_kref, dxgdevice_release); =20 success: - DXG_TRACE("ioctl:%s %s %d", errorstr(ret), __func__, ret); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); return ret; } =20 @@ -3294,7 +3294,209 @@ dxgkio_unlock2(struct dxgprocess *process, void *__= user inargs) kref_put(&device->device_kref, dxgdevice_release); =20 success: - DXG_TRACE("ioctl:%s %s %d", errorstr(ret), __func__, ret); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_update_alloc_property(struct dxgprocess *process, void *__user inar= gs) +{ + struct d3dddi_updateallocproperty args; + int ret; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + args.paging_queue); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_update_alloc_property(process, adapter, + &args, inargs); + +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_query_alloc_residency(struct dxgprocess *process, void *__user inar= gs) +{ + struct d3dkmt_queryallocationresidency args; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if ((args.allocation_count =3D=3D 0) =3D=3D (args.resource.v =3D=3D 0)) { + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + ret =3D dxgvmb_send_query_alloc_residency(process, adapter, &args); +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_set_allocation_priority(struct dxgprocess *process, void *__user in= args) +{ + struct d3dkmt_setallocationpriority args; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + ret =3D dxgvmb_send_set_allocation_priority(process, adapter, &args); +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_get_allocation_priority(struct dxgprocess *process, void *__user in= args) +{ + struct d3dkmt_getallocationpriority args; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + ret =3D dxgvmb_send_get_allocation_priority(process, adapter, &args); +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_change_vidmem_reservation(struct dxgprocess *process, void *__user = inargs) +{ + struct d3dkmt_changevideomemoryreservation args; + int ret; + struct dxgadapter *adapter =3D NULL; + bool adapter_locked =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.process !=3D 0) { + DXG_ERR("setting memory reservation for other process"); + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + adapter_locked =3D true; + args.adapter.v =3D 0; + ret =3D dxgvmb_send_change_vidmem_reservation(process, adapter, + zerohandle, &args); + +cleanup: + + if (adapter_locked) + dxgadapter_release_lock_shared(adapter); + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); return ret; } =20 @@ -4050,7 +4252,8 @@ static struct ioctl_desc ioctls[] =3D { /* 0x13 */ {dxgkio_destroy_allocation, LX_DXDESTROYALLOCATION2}, /* 0x14 */ {dxgkio_enum_adapters, LX_DXENUMADAPTERS2}, /* 0x15 */ {dxgkio_close_adapter, LX_DXCLOSEADAPTER}, -/* 0x16 */ {}, +/* 0x16 */ {dxgkio_change_vidmem_reservation, + LX_DXCHANGEVIDEOMEMORYRESERVATION}, /* 0x17 */ {}, /* 0x18 */ {dxgkio_create_hwqueue, LX_DXCREATEHWQUEUE}, /* 0x19 */ {dxgkio_destroy_device, LX_DXDESTROYDEVICE}, @@ -4070,11 +4273,11 @@ static struct ioctl_desc ioctls[] =3D { /* 0x27 */ {}, /* 0x28 */ {}, /* 0x29 */ {}, -/* 0x2a */ {}, +/* 0x2a */ {dxgkio_query_alloc_residency, LX_DXQUERYALLOCATIONRESIDENCY}, /* 0x2b */ {}, /* 0x2c */ {}, /* 0x2d */ {}, -/* 0x2e */ {}, +/* 0x2e */ {dxgkio_set_allocation_priority, LX_DXSETALLOCATIONPRIORITY}, /* 0x2f */ {}, /* 0x30 */ {}, /* 0x31 */ {dxgkio_signal_sync_object_cpu, @@ -4089,13 +4292,13 @@ static struct ioctl_desc ioctls[] =3D { /* 0x36 */ {dxgkio_submit_wait_to_hwqueue, LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE}, /* 0x37 */ {dxgkio_unlock2, LX_DXUNLOCK2}, -/* 0x38 */ {}, +/* 0x38 */ {dxgkio_update_alloc_property, LX_DXUPDATEALLOCPROPERTY}, /* 0x39 */ {}, /* 0x3a */ {dxgkio_wait_sync_object_cpu, LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU}, /* 0x3b */ {dxgkio_wait_sync_object_gpu, LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU}, -/* 0x3c */ {}, +/* 0x3c */ {dxgkio_get_allocation_priority, LX_DXGETALLOCATIONPRIORITY}, /* 0x3d */ {}, /* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3}, /* 0x3f */ {dxgkio_share_objects, LX_DXSHAREOBJECTS}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index b498f09e694d..af381101fd90 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -668,6 +668,63 @@ struct d3dkmt_submitcommandtohwqueue { #endif }; =20 +struct d3dkmt_setallocationpriority { + struct d3dkmthandle device; + struct d3dkmthandle resource; +#ifdef __KERNEL__ + const struct d3dkmthandle *allocation_list; +#else + __u64 allocation_list; +#endif + __u32 allocation_count; + __u32 reserved; +#ifdef __KERNEL__ + const __u32 *priorities; +#else + __u64 priorities; +#endif +}; + +struct d3dkmt_getallocationpriority { + struct d3dkmthandle device; + struct d3dkmthandle resource; +#ifdef __KERNEL__ + const struct d3dkmthandle *allocation_list; +#else + __u64 allocation_list; +#endif + __u32 allocation_count; + __u32 reserved; +#ifdef __KERNEL__ + __u32 *priorities; +#else + __u64 priorities; +#endif +}; + +enum d3dkmt_allocationresidencystatus { + _D3DKMT_ALLOCATIONRESIDENCYSTATUS_RESIDENTINGPUMEMORY =3D 1, + _D3DKMT_ALLOCATIONRESIDENCYSTATUS_RESIDENTINSHAREDMEMORY =3D 2, + _D3DKMT_ALLOCATIONRESIDENCYSTATUS_NOTRESIDENT =3D 3, +}; + +struct d3dkmt_queryallocationresidency { + struct d3dkmthandle device; + struct d3dkmthandle resource; +#ifdef __KERNEL__ + struct d3dkmthandle *allocations; +#else + __u64 allocations; +#endif + __u32 allocation_count; + __u32 reserved; +#ifdef __KERNEL__ + enum d3dkmt_allocationresidencystatus *residency_status; +#else + __u64 residency_status; +#endif +}; + struct d3dddicb_lock2flags { union { struct { @@ -835,6 +892,11 @@ struct d3dkmt_destroyallocation2 { struct d3dddicb_destroyallocation2flags flags; }; =20 +enum d3dkmt_memory_segment_group { + _D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL =3D 0, + _D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL =3D 1 +}; + struct d3dkmt_adaptertype { union { struct { @@ -886,6 +948,61 @@ struct d3dddi_openallocationinfo2 { __u64 reserved[6]; }; =20 +struct d3dddi_updateallocproperty_flags { + union { + struct { + __u32 accessed_physically:1; + __u32 reserved:31; + }; + __u32 value; + }; +}; + +struct d3dddi_segmentpreference { + union { + struct { + __u32 segment_id0:5; + __u32 direction0:1; + __u32 segment_id1:5; + __u32 direction1:1; + __u32 segment_id2:5; + __u32 direction2:1; + __u32 segment_id3:5; + __u32 direction3:1; + __u32 segment_id4:5; + __u32 direction4:1; + __u32 reserved:2; + }; + __u32 value; + }; +}; + +struct d3dddi_updateallocproperty { + struct d3dkmthandle paging_queue; + struct d3dkmthandle allocation; + __u32 supported_segment_set; + struct d3dddi_segmentpreference preferred_segment; + struct d3dddi_updateallocproperty_flags flags; + __u64 paging_fence_value; + union { + struct { + __u32 set_accessed_physically:1; + __u32 set_supported_segmentSet:1; + __u32 set_preferred_segment:1; + __u32 reserved:29; + }; + __u32 property_mask_value; + }; +}; + +struct d3dkmt_changevideomemoryreservation { + __u64 process; + struct d3dkmthandle adapter; + enum d3dkmt_memory_segment_group memory_segment_group; + __u64 reservation; + __u32 physical_adapter_index; +}; + struct d3dkmt_createhwqueue { struct d3dkmthandle context; struct d3dddi_createhwqueueflags flags; @@ -1099,6 +1216,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x14, struct d3dkmt_enumadapters2) #define LX_DXCLOSEADAPTER \ _IOWR(0x47, 0x15, struct d3dkmt_closeadapter) +#define LX_DXCHANGEVIDEOMEMORYRESERVATION \ + _IOWR(0x47, 0x16, struct d3dkmt_changevideomemoryreservation) #define LX_DXCREATEHWQUEUE \ _IOWR(0x47, 0x18, struct d3dkmt_createhwqueue) #define LX_DXDESTROYHWQUEUE \ @@ -1111,6 +1230,10 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) #define LX_DXLOCK2 \ _IOWR(0x47, 0x25, struct d3dkmt_lock2) +#define LX_DXQUERYALLOCATIONRESIDENCY \ + _IOWR(0x47, 0x2a, struct d3dkmt_queryallocationresidency) +#define LX_DXSETALLOCATIONPRIORITY \ + _IOWR(0x47, 0x2e, struct d3dkmt_setallocationpriority) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x31, struct d3dkmt_signalsynchronizationobjectfromcpu) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU \ @@ -1125,10 +1248,14 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x36, struct d3dkmt_submitwaitforsyncobjectstohwqueue) #define LX_DXUNLOCK2 \ _IOWR(0x47, 0x37, struct d3dkmt_unlock2) +#define LX_DXUPDATEALLOCPROPERTY \ + _IOWR(0x47, 0x38, struct d3dddi_updateallocproperty) #define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x3a, struct d3dkmt_waitforsynchronizationobjectfromcpu) #define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU \ _IOWR(0x47, 0x3b, struct d3dkmt_waitforsynchronizationobjectfromgpu) +#define LX_DXGETALLOCATIONPRIORITY \ + _IOWR(0x47, 0x3c, struct d3dkmt_getallocationpriority) #define LX_DXENUMADAPTERS3 \ _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) #define LX_DXSHAREOBJECTS \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f53.google.com (mail-wr1-f53.google.com [209.85.221.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A69FC3FA5D1 for ; Thu, 19 Mar 2026 20:25:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951941; cv=none; b=tmIPReE0EwLd2R8NV3bzE1D8UZ+3QSbT0rqMb05OCxrEjYQ8wO5OE+PJqp12zGgk6Y3dhTwKLeZNpGWlgH2BH2SYEaZ7VzjibcmHOa6jRFJyKw6E9/j6GGcXcrI7XpDNlGePyOCxfl/FxAeQ6hZd3wgqmuhdSWr740Oing47pqU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951941; c=relaxed/simple; bh=ZZXM/wQLEF3Dlc1WRi+Ywkz6l4XsJGiFvg+NN8EbAPA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZK6wsiVQBqUdKxcDoCPl9jWgJ0GAnzdn0OetNpsuNxHeWirlCmTRvGWNMRMLnYA7kNDi9IujS2Xq8ip1fwtmJ9tyq1bCahWuMQIWlKxKShAaCLX4yLKVySbdr6gUxDK9t934+x5GhGhqzT5lqaMUf/z7ibYtdgqvLiVtgBng/Cg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Dlx7kWLW; arc=none smtp.client-ip=209.85.221.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Dlx7kWLW" Received: by mail-wr1-f53.google.com with SMTP id ffacd0b85a97d-43b44c0bcdbso1002994f8f.1 for ; Thu, 19 Mar 2026 13:25:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951936; x=1774556736; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=o+dl+0/EV/hQJnho7KuWFmDHSw/Nz/kLByx2i7vctfo=; b=Dlx7kWLWagdirKqW1Z1JhgJuK1VZxHadmH9cOca0JO3OfNzUBL5y4w+1QSS2PDUf56 jMw21qW7q/x/QDC39CDM/6p/6vDcfnVw0kI7VxchXsPNingow5rXdxbdemMH3+8G0uz+ Bz5gn51xtPiQ83yVVMlNGB3zx77coqPyZR8fKS/e7+AcG7C2ykSMZCN7WDPl1369KCVv NPr+xSoUWSP/aLuHdCpvAsZ+1x7Xb7ZMx61JnBuWj8q6G0i0nfo85gSFHZ3FzbuG5akb y7P4H/C2eKhczGPBapKzqowxyoyVRynGSFiyOIno0rLXiADRCg4MdH4BCGnZDxQmzfG2 uPTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951936; x=1774556736; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=o+dl+0/EV/hQJnho7KuWFmDHSw/Nz/kLByx2i7vctfo=; b=Xr/0FaaSEVTW5Hgk9sRSSo0Yr+JOiatslGPiUKkDlMliw3ORa+/hVO81TcUFc+Bo7h mqGRNooqy/c3kfQ8R2B4URF6fH15uTMPH6wx5fOvLGipt9uMoieGYpuh7duvJuJfEB7y wGe5+WC6qnz/2jjf+OnDRjcsdJoXN0XFreb9WVnVsMkscyi7t1nnZUdN8VIm8vyQkr23 upUsM1ahpjc8VUngP/Rwur1k8gVYps8KtxG+tbCfUarUzZFNBt7mWBau3MGjeiy5/z2X EuSMqYFMt3ecydPwpD+aKoE9TB/qBmuOFeXxncppkPQJtL0PvCG5q5ZCYtHfmFpQF5M9 wHuw== X-Gm-Message-State: AOJu0YyC+w4CvWNhXFz5BoZlCZjMy48aaVAZL1TVa9dw25+S9/f2sEMd dvWEnaBURAex5lpMkVb3FvGgpqEopkHxa877ZUUeZ1ePwYUpM5YtPEGT X-Gm-Gg: ATEYQzziu08WxVx8aXJIfipMPkngB+sXAngPCOZ3zffVfxm2ggiLbZznRTwHmS+wE+c 3Aetb/Hb8NelL69rX3XVRxiZwxTe+psOcb4y2qyGo4e+n+xv1Jje6eiacsFB1yWXr/Y01DmI33U bT218bEUd7cC3RhX3Pdv7DHgxQm+/9jytOAHjn3lpeFwzcf33w7qL+4wxip2lHhODKkSZUf0lUF Vtq1BUfBhJRMmzSlBzKDscuYS6LdTprAHf5w9Jdbw3RG855X7Dr9lF4MWsSlHdib/TTBmLDinZ7 bcdk4k4W5qxdgBf23B4e6CflDqhtLKB0Ls2+F8jqjZWOfAkvZvvObCUOA02OLfcYa5IX6JOZLmU GpXx/80fCU8Yhwp926uMdM35XZFQ+wj6abx3BYP71nFohaKD+IesgGQOP9iKUH45hKk8Ba86iQu h38TyrqvfXwMOPKXIyVemYoRKCjI3aCrh1fuqao1iv9RXpXQXt X-Received: by 2002:a05:6000:420a:b0:43b:498f:dcec with SMTP id ffacd0b85a97d-43b6423287dmr1269710f8f.3.1773951935676; Thu, 19 Mar 2026 13:25:35 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.34 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:35 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 19/55] drivers: hv: dxgkrnl: Flush heap transitions Date: Thu, 19 Mar 2026 20:24:33 +0000 Message-ID: <20260319202509.63802-20-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement the ioctl to flush heap transitions (LX_DXFLUSHHEAPTRANSITIONS). The ioctl is used to ensure that the video memory manager on the host flushes all internal operations. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgadapter.c | 2 +- drivers/hv/dxgkrnl/dxgkrnl.h | 3 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 23 ++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 5 ++++ drivers/hv/dxgkrnl/ioctl.c | 49 ++++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 6 ++++ 6 files changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index 23f00db7637e..6f763e326a65 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -942,7 +942,7 @@ else if (alloc->priv_drv_data) vfree(alloc->priv_drv_data); if (alloc->cpu_address_mapped) - pr_err("Alloc IO space is mapped: %p", alloc); + DXG_ERR("Alloc IO space is mapped: %p", alloc); kfree(alloc); } =20 diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 7fefe4617488..ced9dd294f5f 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -882,6 +882,9 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess *p= rocess, int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_submitcommandtohwqueue *a); +int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_flushheaptransitions *arg); int dxgvmb_send_open_sync_object_nt(struct dxgprocess *process, struct dxgvmbuschannel *channel, struct d3dkmt_opensyncobjectfromnthandle2 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index dd2c97fee27b..928fad5f133b 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1829,6 +1829,29 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess= *process, return ret; } =20 +int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_flushheaptransitions *args) +{ + struct dxgkvmb_command_flushheaptransitions *command; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_FLUSHHEAPTRANSITIONS, + process->host_handle); + ret =3D 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 dbb01b9ab066..d232eb234e2c 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -367,6 +367,11 @@ struct dxgkvmb_command_submitcommandtohwqueue { /* PrivateDriverData */ }; =20 +/* Returns ntstatus */ +struct dxgkvmb_command_flushheaptransitions { + struct dxgkvmb_command_vgpu_to_host hdr; +}; + struct dxgkvmb_command_createallocation_allocinfo { u32 flags; u32 priv_drv_data_size; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index b626e2518ff2..8b7d00e4c881 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3500,6 +3500,53 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *= process, void *__user inargs return ret; } =20 +static int +dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user ina= rgs) +{ + struct d3dkmt_flushheaptransitions args; + int ret; + struct dxgadapter *adapter =3D NULL; + bool adapter_locked =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + adapter_locked =3D true; + + args.adapter =3D adapter->host_handle; + ret =3D dxgvmb_send_flush_heap_transitions(process, adapter, &args); + if (ret < 0) + goto cleanup; + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy output args"); + ret =3D -EINVAL; + } + +cleanup: + + if (adapter_locked) + dxgadapter_release_lock_shared(adapter); + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + return ret; +} + static int dxgkio_get_device_state(struct dxgprocess *process, void *__user inargs) { @@ -4262,7 +4309,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x1c */ {dxgkio_destroy_paging_queue, LX_DXDESTROYPAGINGQUEUE}, /* 0x1d */ {dxgkio_destroy_sync_object, LX_DXDESTROYSYNCHRONIZATIONOBJECT}, /* 0x1e */ {}, -/* 0x1f */ {}, +/* 0x1f */ {dxgkio_flush_heap_transitions, LX_DXFLUSHHEAPTRANSITIONS}, /* 0x20 */ {}, /* 0x21 */ {}, /* 0x22 */ {}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index af381101fd90..873feb951129 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -936,6 +936,10 @@ struct d3dkmt_queryadapterinfo { __u32 private_data_size; }; =20 +struct d3dkmt_flushheaptransitions { + struct d3dkmthandle adapter; +}; + struct d3dddi_openallocationinfo2 { struct d3dkmthandle allocation; #ifdef __KERNEL__ @@ -1228,6 +1232,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x19, struct d3dkmt_destroydevice) #define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) +#define LX_DXFLUSHHEAPTRANSITIONS \ + _IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions) #define LX_DXLOCK2 \ _IOWR(0x47, 0x25, struct d3dkmt_lock2) #define LX_DXQUERYALLOCATIONRESIDENCY \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BAEF13F9F4F for ; Thu, 19 Mar 2026 20:25:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951943; cv=none; b=WEVjDWYpR0ctlqrjT1OFX7vcK8nIGh/EoZ84x5D+8d5PtyLbPjENnKFD/l4RlSHxVGyX5+JbYLK8BlFLegjEbQ+m9nNMSKARCVTr/A4KwUbBVn4iDAx/6o1H3XGPieSDF+oRan+IxdeMArKG8iqY2nB+JsJyeKdO7UozBndXSqY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951943; c=relaxed/simple; bh=JSyEBFM7jldu6kjAQplAK3yqus2O6kfa1DeMHqQHv4U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cISYViVaivs53iI84zKZFaOVuJp7kM2Pqp34tLxlVzJxcshd2axmfAxHxFBpUMQOBaMwEQa02ZnQ/24AosmNqGJlhZVNdv2zN6LUhij4qXmPRbOCB/phvNuXmqqckGvYDaXPTVrJ7H/KgVpLNXzdvX0+Gvo27CK5ggyLQPgSKNk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=b6wRcKbE; arc=none smtp.client-ip=209.85.221.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="b6wRcKbE" Received: by mail-wr1-f42.google.com with SMTP id ffacd0b85a97d-439b97a8a8cso1312825f8f.1 for ; Thu, 19 Mar 2026 13:25:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951937; x=1774556737; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=SXo/15R90aCs7ovxarZsZGx/BAt8UKSFyqYHwOlOjpI=; b=b6wRcKbEut0E8iDYg9vSckFTr04txJEtyAWlo3qOqD7M0ieAnqiIRzJr5an3dbSvaL K5pkcxUd5/Y5NnAoe0ROFC3u3v1FwkuHujShvHTGn2PGPUYpRTMom7BdPc6i8wJezh2G GoL2sxCcS40W5p6hxStIprkkyfOnmayOkS+ZXPLb2e0/H+m+dEBt+pFsBeNkwYxpZi0v cdsxx0/aO+wH9kP85jEq1PGYqN1z4NXFwAflErock1PjY+7pAmnhZWU9deEE9gMuK/TE 1HIIoKi3F8nQtxkMfGWnBQlOXMyUMRy8nAcrODBjn2IyE7lpERZTmJUaeIy+oVmVZiGo lE0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951937; x=1774556737; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=SXo/15R90aCs7ovxarZsZGx/BAt8UKSFyqYHwOlOjpI=; b=ZuQMmrwvCn2zp3FcEwPWop0YFbXZR7VkkYx4aSQteWkZEYkrQ1YTfLTHB2T1WWT6q9 9fqFMiAvvOTX0ytrPb5S0eGGpMzL27xID77CwVO0vzqvy5KbXt1iPoXX4zohKolFsJwV LWBdtxPmr5ziYU+c1EX0WkEEk+xz59MM5X6fj7YtWMTjarFM3KBQgLxbjYssi//Y2B/b RYJDzk3c0rhK2+Czn5QJZuDY5V4WRq/ff7Iiblw22mRAQNNeQUyfk/YDn10bB4VzdXw9 t8dmlJXauGYEyyptbizdNfaao4T655xju3e2ZGFRLMY9GYb2BWVV3qzessgbtg0x4ATK MsXw== X-Gm-Message-State: AOJu0YykfTPFJoWAxsAV65BaSHzFSWNNfLMZSZVUCjKr4ScTrpAvtzl8 4BuEMUA/9JhoyrdcxSafuH9B6hYQhgcNy1yGXSYCjKQuCbMbJVO+QiiJ X-Gm-Gg: ATEYQzyQ3VEUW7xRDaHqe35X3pnB4jUZzBKS4mRex7OUQEJv9j5llm1q0HcltV9ecxe ZX232X2OvYMwFVtLASDjynaUhcm5jGtJ2gFLjymvmmvSFcMVLJJl7BeIxYoRxQ4Ds5PLZJvKiCR On+SVbLzhcams90J2oZG6/rlEHNZravC7BxxXHD53A+3obL0xTtrlfSMc7m17Zp3pQSv9To1au3 /IbE9A2gWPtVvAZfUD4Slhmd7xFpzKBgaLKzUrf5whv41LT6vFPhknQAqz+XsTTEmfCqLbbopnf 7+w6vZHLDvhG7qs77FY26cs+RkM+4eECfYghOyeLatW3OsT/Dif32AIer1dYq5lEQBSbt6Bh8dM 2Kb0Bx0Det2Lfowodtyc/p2jlWq0m9eVzYwkASVpNup0KxFyjUlWi1rT0HBWJbwWn/eYnzSkKfX 55qZ161T6a/GQEhcqqRbm7g+IP5qD3dVZ5C+ngu1DyHFyaVwXj X-Received: by 2002:a05:6000:24c3:b0:439:b60a:b400 with SMTP id ffacd0b85a97d-43b64263f07mr1140495f8f.31.1773951936809; Thu, 19 Mar 2026 13:25:36 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.35 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:36 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 20/55] drivers: hv: dxgkrnl: Query video memory information Date: Thu, 19 Mar 2026 20:24:34 +0000 Message-ID: <20260319202509.63802-21-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement the ioctl to query video memory information from the host (LX_DXQUERYVIDEOMEMORYINFO). Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 5 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 64 +++++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 14 ++++++++ drivers/hv/dxgkrnl/ioctl.c | 50 ++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 13 +++++++ 5 files changed, 145 insertions(+), 1 deletion(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index ced9dd294f5f..b6a7288a4177 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -894,6 +894,11 @@ int dxgvmb_send_query_alloc_residency(struct dxgproces= s *process, struct dxgadapter *adapter, struct d3dkmt_queryallocationresidency *args); +int dxgvmb_send_query_vidmem_info(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryvideomemoryinfo *args, + struct d3dkmt_queryvideomemoryinfo + *__user iargs); int dxgvmb_send_get_device_state(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_getdevicestate *args, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 928fad5f133b..48ff49456057 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1925,6 +1925,70 @@ int dxgvmb_send_query_alloc_residency(struct dxgproc= ess *process, return ret; } =20 +int dxgvmb_send_query_vidmem_info(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryvideomemoryinfo *args, + struct d3dkmt_queryvideomemoryinfo *__user + output) +{ + int ret; + struct dxgkvmb_command_queryvideomemoryinfo *command; + struct dxgkvmb_command_queryvideomemoryinfo_return result =3D { }; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + command_vgpu_to_host_init2(&command->hdr, + dxgk_vmbcommand_queryvideomemoryinfo, + process->host_handle); + command->adapter =3D args->adapter; + command->memory_segment_group =3D args->memory_segment_group; + command->physical_adapter_index =3D args->physical_adapter_index; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(&output->budget, &result.budget, + sizeof(output->budget)); + if (ret) { + pr_err("%s failed to copy budget", __func__); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D copy_to_user(&output->current_usage, &result.current_usage, + sizeof(output->current_usage)); + if (ret) { + pr_err("%s failed to copy current usage", __func__); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D copy_to_user(&output->current_reservation, + &result.current_reservation, + sizeof(output->current_reservation)); + if (ret) { + pr_err("%s failed to copy reservation", __func__); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D copy_to_user(&output->available_for_reservation, + &result.available_for_reservation, + sizeof(output->available_for_reservation)); + if (ret) { + pr_err("%s failed to copy avail reservation", __func__); + ret =3D -EINVAL; + } + +cleanup: + free_message(&msg, process); + if (ret) + dev_dbg(DXGDEV, "err: %d", ret); + return ret; +} + int dxgvmb_send_get_device_state(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_getdevicestate *args, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index d232eb234e2c..a1549983d50f 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -664,6 +664,20 @@ struct dxgkvmb_command_queryallocationresidency_return= { /* d3dkmt_allocationresidencystatus[NumAllocations] */ }; =20 +struct dxgkvmb_command_queryvideomemoryinfo { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle adapter; + enum d3dkmt_memory_segment_group memory_segment_group; + u32 physical_adapter_index; +}; + +struct dxgkvmb_command_queryvideomemoryinfo_return { + u64 budget; + u64 current_usage; + u64 current_reservation; + u64 available_for_reservation; +}; + struct dxgkvmb_command_getdevicestate { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmt_getdevicestate args; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 8b7d00e4c881..e692b127e219 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3547,6 +3547,54 @@ dxgkio_flush_heap_transitions(struct dxgprocess *pro= cess, void *__user inargs) return ret; } =20 +static int +dxgkio_query_vidmem_info(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_queryvideomemoryinfo args; + int ret; + struct dxgadapter *adapter =3D NULL; + bool adapter_locked =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.process !=3D 0) { + DXG_ERR("query vidmem info from another process"); + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + adapter_locked =3D true; + + args.adapter =3D adapter->host_handle; + ret =3D dxgvmb_send_query_vidmem_info(process, adapter, &args, inargs); + +cleanup: + + if (adapter_locked) + dxgadapter_release_lock_shared(adapter); + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + if (ret < 0) + DXG_ERR("failed: %x", ret); + return ret; +} + static int dxgkio_get_device_state(struct dxgprocess *process, void *__user inargs) { @@ -4287,7 +4335,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x07 */ {dxgkio_create_paging_queue, LX_DXCREATEPAGINGQUEUE}, /* 0x08 */ {}, /* 0x09 */ {dxgkio_query_adapter_info, LX_DXQUERYADAPTERINFO}, -/* 0x0a */ {}, +/* 0x0a */ {dxgkio_query_vidmem_info, LX_DXQUERYVIDEOMEMORYINFO}, /* 0x0b */ {}, /* 0x0c */ {}, /* 0x0d */ {}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 873feb951129..b7d8b1d91cfc 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -897,6 +897,17 @@ enum d3dkmt_memory_segment_group { _D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL =3D 1 }; =20 +struct d3dkmt_queryvideomemoryinfo { + __u64 process; + struct d3dkmthandle adapter; + enum d3dkmt_memory_segment_group memory_segment_group; + __u64 budget; + __u64 current_usage; + __u64 current_reservation; + __u64 available_for_reservation; + __u32 physical_adapter_index; +}; + struct d3dkmt_adaptertype { union { struct { @@ -1204,6 +1215,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x07, struct d3dkmt_createpagingqueue) #define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) +#define LX_DXQUERYVIDEOMEMORYINFO \ + _IOWR(0x47, 0x0a, struct d3dkmt_queryvideomemoryinfo) #define LX_DXGETDEVICESTATE \ _IOWR(0x47, 0x0e, struct d3dkmt_getdevicestate) #define LX_DXSUBMITCOMMAND \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A29043FA5E0 for ; Thu, 19 Mar 2026 20:25:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951944; cv=none; b=IK1ZRYFbtfr6oiK1lyYMuJ27G6UlL9h6M1u6D1oo4cT2iCrFlW0bM2jCAPoW035Rvc8q2/N80aQ9lK/Hp45Luut2Pr/Ut8+rrIzVAfptsaGqU8bKsWtNyPop7cH5EMUAujzyNXqcrDmEC/HwBROPm5uZN1aTVbwgF3IhgSMKB9Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951944; c=relaxed/simple; bh=S8QKX0NZSQwSO6HdzqOHD5S8SMoE062+vSMVmXGkj2U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=f8bAeQEOzsoxFTEMWZyjB71IB/H+T8RdqEYtxYIe+ftuWIx253YAW7jR3BoB6qdeoo7YzSR1/5OtMQ9iu8EIUPU8DL7kzjG3Msm5TJNXdUPBrsAq1fjbukA3tm+om4SwLpb7V5IxofJg+qlyQwindO/h2IYjg/Wrk/41QNMiXQI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=IPsAoz0A; arc=none smtp.client-ip=209.85.221.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IPsAoz0A" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-439b9cf8cb5so1714761f8f.0 for ; Thu, 19 Mar 2026 13:25:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951938; x=1774556738; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=qrH2a5k/EhZDhIUyy4Q/uQ6n7kgRZKjSjI2+9Ckr7IY=; b=IPsAoz0AVJrPIESWw78xjrgdsEUq+Ch0E9HQAnupYtWJzSeL5HmXdmSBs6BbKUHR2w +Y9Bh9WEpkXlpA1Ot3RcMyYOQt49ulAbs4rufJ4QcQ1WA1YPev2YEzqWoBxw/c5/E7gi ZMD39FPb3r4wRIUoQFUti197OU6wEbUZFZ6hRrec1ju/QhdQ12LRlSsHea+iORAdhXxW ILkxL2meMWzWHNhwcOn8Au2sGxgEKSNYEoC9x4XIOlAy33ZcoacnQ8iYX8gCtGsZ5gT0 GReYFGStdcJtuq6PuEesnDB1Zj5WnTLypmcvxxE461B/g76oLK0BdQuk/ZUyH+p5nZoK +jTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951938; x=1774556738; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=qrH2a5k/EhZDhIUyy4Q/uQ6n7kgRZKjSjI2+9Ckr7IY=; b=rhQd95JmtoGvuUzvNnl8e2gtoR8FAtl73vpLXuGObJDa83YFylkMJJMGu329XHjUC7 aAr0HoypYOST+vGoMsIacQS5KaxeVYFopj6EvYx/M6onwfqOBDlJYBPrjG6XksCZyS8n jh6XcwyeQARC9WrEyaTPW9lAXYe/3qA5T7lJ02MgEx2EhkSC5Azz+cxamuxzKtaRRNmg PB24HARg/Rjuau8kMZm01h23Fk19JggTszVS9ioHCaMZ065f0VwRZM2WlNf0C0SYrDim dNd2rXh0LJtaa0Un+1AaMQeMeD2CpCiw2eIoZ0y+xs2CWxFeqCr9nLYdstxLKvu6npGA 4huw== X-Gm-Message-State: AOJu0Yxmp3q11O4FIu2yZf/iWCsqvuMJ1IYj1+Sm9bw6eGN9QtW6zhoP 4RMUruLCpnyD9laJAapDOmiZXoD5FntCDQhG/uiea1hoGHqvkzF8EHqA X-Gm-Gg: ATEYQzxHtZH0xZhoWvSPiYhfBcb/pVZ8p8U1j9Y+2sRzw9//MT7x0+7sxR3tVvcVUMZ DHZpD/d9StTc4ZFsDk/5GSAn8FrSGRoIW0VDFsq8PWEaC0r5m3/SP+4FO99LRgaIB288f8hKPSa AFe0tDC/k8GYF3WJ7Qk2mJvF0GimBa4uv09IYYX1uJY87A+1XYq2GZsrrE8Gq7v6jaJmR84yIem RPTzaUVJ93KolsDw0eDOjIWxJ0mWT9NxOVkFliVm3h+sxVXN5WLFk5FEGlRpTBdnVlWprz69UkR RdJnCQo+ZKEVbFPSSf2OYoeQWrrP6qnxs75+11scVOtovF0xXjJZBxA85mKEqv5Vk7/kizyn6aa fmfxZfUGKZbbc2AY5acE9vp9ffVnc9HS0Z5JVabRhBUEhTIyGuO92Ms11ALl/opWQj8VPJCR2Zc vD3zNvx885fUUWLb7aAc6+BgbO8NA4p43Z/52R4iVrAM9Ly3Ie X-Received: by 2002:a05:6000:2089:b0:43b:5356:a7fc with SMTP id ffacd0b85a97d-43b6428b374mr1145476f8f.55.1773951937820; Thu, 19 Mar 2026 13:25:37 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.36 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:37 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 21/55] drivers: hv: dxgkrnl: The escape ioctl Date: Thu, 19 Mar 2026 20:24:35 +0000 Message-ID: <20260319202509.63802-22-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement the escape ioctl (LX_DXESCAPE). This ioctl is used to send/receive private data between user mode compute device driver (guest) and kernel mode compute device driver (host). It allows the user mode driver to extend the virtual compute device API. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 3 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 75 ++++++++++++++++++++++++++++++++--- drivers/hv/dxgkrnl/dxgvmbus.h | 12 ++++++ drivers/hv/dxgkrnl/ioctl.c | 42 +++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 41 +++++++++++++++++++ 5 files changed, 167 insertions(+), 6 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index b6a7288a4177..dafc721ed6cf 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -894,6 +894,9 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess= *process, struct dxgadapter *adapter, struct d3dkmt_queryallocationresidency *args); +int dxgvmb_send_escape(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_escape *args); 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 48ff49456057..8bdd49bc7aa6 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1925,6 +1925,70 @@ int dxgvmb_send_query_alloc_residency(struct dxgproc= ess *process, return ret; } =20 +int dxgvmb_send_escape(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_escape *args) +{ + int ret; + struct dxgkvmb_command_escape *command =3D NULL; + u32 cmd_size =3D sizeof(*command); + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + if (args->priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EINVAL; + goto cleanup; + } + + cmd_size =3D cmd_size - sizeof(args->priv_drv_data[0]) + + args->priv_drv_data_size; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_ESCAPE, + process->host_handle); + command->adapter =3D args->adapter; + command->device =3D args->device; + command->type =3D args->type; + command->flags =3D args->flags; + command->priv_drv_data_size =3D args->priv_drv_data_size; + command->context =3D args->context; + if (args->priv_drv_data_size) { + ret =3D 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 =3D -EINVAL; + goto cleanup; + } + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + command->priv_drv_data, + args->priv_drv_data_size); + if (ret < 0) + goto cleanup; + + if (args->priv_drv_data_size) { + ret =3D 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 =3D -EINVAL; + } + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_vidmem_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryvideomemoryinfo *args, @@ -1955,14 +2019,14 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess= *process, ret =3D copy_to_user(&output->budget, &result.budget, sizeof(output->budget)); if (ret) { - pr_err("%s failed to copy budget", __func__); + DXG_ERR("failed to copy budget"); ret =3D -EINVAL; goto cleanup; } ret =3D copy_to_user(&output->current_usage, &result.current_usage, sizeof(output->current_usage)); if (ret) { - pr_err("%s failed to copy current usage", __func__); + DXG_ERR("failed to copy current usage"); ret =3D -EINVAL; goto cleanup; } @@ -1970,7 +2034,7 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess *= process, &result.current_reservation, sizeof(output->current_reservation)); if (ret) { - pr_err("%s failed to copy reservation", __func__); + DXG_ERR("failed to copy reservation"); ret =3D -EINVAL; goto cleanup; } @@ -1978,14 +2042,14 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess= *process, &result.available_for_reservation, sizeof(output->available_for_reservation)); if (ret) { - pr_err("%s failed to copy avail reservation", __func__); + DXG_ERR("failed to copy avail reservation"); ret =3D -EINVAL; } =20 cleanup: free_message(&msg, process); if (ret) - dev_dbg(DXGDEV, "err: %d", ret); + DXG_TRACE("err: %d", ret); return ret; } =20 @@ -3152,3 +3216,4 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgproc= ess *process, DXG_TRACE("err: %d", ret); return ret; } + diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index a1549983d50f..e1c2ed7b1580 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -664,6 +664,18 @@ struct dxgkvmb_command_queryallocationresidency_return= { /* d3dkmt_allocationresidencystatus[NumAllocations] */ }; =20 +/* Returns only private data */ +struct dxgkvmb_command_escape { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle adapter; + struct d3dkmthandle device; + enum d3dkmt_escapetype type; + struct d3dddi_escapeflags flags; + u32 priv_drv_data_size; + struct d3dkmthandle context; + u8 priv_drv_data[1]; +}; + struct dxgkvmb_command_queryvideomemoryinfo { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmthandle adapter; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index e692b127e219..78de76abce2d 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3547,6 +3547,46 @@ dxgkio_flush_heap_transitions(struct dxgprocess *pro= cess, void *__user inargs) return ret; } =20 +static int +dxgkio_escape(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_escape args; + int ret; + struct dxgadapter *adapter =3D NULL; + bool adapter_locked =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + adapter_locked =3D true; + + args.adapter =3D adapter->host_handle; + ret =3D dxgvmb_send_escape(process, adapter, &args); + +cleanup: + + if (adapter_locked) + dxgadapter_release_lock_shared(adapter); + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_query_vidmem_info(struct dxgprocess *process, void *__user inargs) { @@ -4338,7 +4378,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x0a */ {dxgkio_query_vidmem_info, LX_DXQUERYVIDEOMEMORYINFO}, /* 0x0b */ {}, /* 0x0c */ {}, -/* 0x0d */ {}, +/* 0x0d */ {dxgkio_escape, LX_DXESCAPE}, /* 0x0e */ {dxgkio_get_device_state, LX_DXGETDEVICESTATE}, /* 0x0f */ {dxgkio_submit_command, LX_DXSUBMITCOMMAND}, /* 0x10 */ {dxgkio_create_sync_object, LX_DXCREATESYNCHRONIZATIONOBJECT}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index b7d8b1d91cfc..749edf28bd43 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -236,6 +236,45 @@ struct d3dddi_destroypagingqueue { struct d3dkmthandle paging_queue; }; =20 +enum d3dkmt_escapetype { + _D3DKMT_ESCAPE_DRIVERPRIVATE =3D 0, + _D3DKMT_ESCAPE_VIDMM =3D 1, + _D3DKMT_ESCAPE_VIDSCH =3D 3, + _D3DKMT_ESCAPE_DEVICE =3D 4, + _D3DKMT_ESCAPE_DRT_TEST =3D 8, +}; + +struct d3dddi_escapeflags { + union { + struct { + __u32 hardware_access:1; + __u32 device_status_query:1; + __u32 change_frame_latency:1; + __u32 no_adapter_synchronization:1; + __u32 reserved:1; + __u32 virtual_machine_data:1; + __u32 driver_known_escape:1; + __u32 driver_common_escape:1; + __u32 reserved2:24; + }; + __u32 value; + }; +}; + +struct d3dkmt_escape { + struct d3dkmthandle adapter; + struct d3dkmthandle device; + enum d3dkmt_escapetype type; + struct d3dddi_escapeflags flags; +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + __u32 priv_drv_data_size; + struct d3dkmthandle context; +}; + enum dxgk_render_pipeline_stage { _DXGK_RENDER_PIPELINE_STAGE_UNKNOWN =3D 0, _DXGK_RENDER_PIPELINE_STAGE_INPUT_ASSEMBLER =3D 1, @@ -1217,6 +1256,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) #define LX_DXQUERYVIDEOMEMORYINFO \ _IOWR(0x47, 0x0a, struct d3dkmt_queryvideomemoryinfo) +#define LX_DXESCAPE \ + _IOWR(0x47, 0x0d, struct d3dkmt_escape) #define LX_DXGETDEVICESTATE \ _IOWR(0x47, 0x0e, struct d3dkmt_getdevicestate) #define LX_DXSUBMITCOMMAND \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AFE023F8DF0 for ; Thu, 19 Mar 2026 20:25:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951944; cv=none; b=gq4TUK/CYoW+BUBijMulA2kY8kzgBtd7mzhagFx3Oom3hIYonkPCPcLRoiMqut2d/mrULwTZW/zzc033UDgcI5jpFXeBPj/QAP9FY6HFk09ppNrOMYIL42QPqnl7S8mD3buoZa400LWc/jRhE8KTYIzfmkfzO6Vd6+ef/4EbnPQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951944; c=relaxed/simple; bh=G5yS/0Ks2668HL0F929eJ2RnsQeUhgHqOkkBonyENwU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=s13xs36/QDIwgrnDULKEYANl8yLQHWigSk1WnPQn14C8af/zBHYzhgU5O0RhB7eWv4YKW7AnMblqoQqqlaopSkef1DoxXkSPpyUatbS6pyVQgoGSmR6i3nLqDVSxQNsC6d869wbzi5bPnh/GoSwisOHTr2bY9rzJ1lNWNYxRewQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Gp1VzVVa; arc=none smtp.client-ip=209.85.221.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Gp1VzVVa" Received: by mail-wr1-f44.google.com with SMTP id ffacd0b85a97d-439bcec8613so990720f8f.3 for ; Thu, 19 Mar 2026 13:25:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951939; x=1774556739; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9gpXwUuuqUKCEuabXGr3mbEIEr9EepzLK4R1EIs1rd0=; b=Gp1VzVValD8gVa2YZH0HJYNR5MSHLfTCiRalkgEJi5ltJJdKzD2hdB/qwJnBI1zxLJ 8hp/qCi5B/DupdqTq0Pq8oURN3KqpapxYXm4TteoRx6cbPxJvNdGXp/+fbhIbkDfn9Ux SdklvUa7UG/PXeqtC4K78slgjH2Gv+JtKQQYmdlqHrv67rWPe24DUANL95bWbsMLkQef RwVMR3AuCcgoj8tm0SVKom9yWgcMjlpVrGraDMhWAzh+M9FWaEyNtx0SO+BFaCCwkaZF +VZL+9tAI0swpMUufPL4lWlw9zQCQ9iGYvrg3ef9n4ePlsa9rf+VXuSYyfK7Idi+tikg jacw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951939; x=1774556739; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=9gpXwUuuqUKCEuabXGr3mbEIEr9EepzLK4R1EIs1rd0=; b=Dr9ekK0HrKcVnok0wwogu897WREOQimMrhyQdbwIvi6pkdun9f3VYDi8fI/AFok/J4 DEdQ6knSerlCUaj4gRzmf1LaQqbPAEEa/Gk+YpO7HU2+6KWXGohsjnvb9LABuOZ3evdF of5Jvyr2LD/MK5B3neeFZvshQCNM59R1GJka++KoOIn7URqG6Kw5FpogUHpzDfqyV6Oy 8NQCdLgv6qAa9YWo5gfHXz2zjluQ7RqqjcUkDgavD1ey9B1fWHU3+f2I2UsLSIw4lqP8 xvTcn7bw06v0Qwg69IJGJ/AkfYUuLQduIsfiGsO5A/W3MD/CBdlndjitb8Jarw3dtp80 PZSA== X-Gm-Message-State: AOJu0Yy4XG09+ehCHDMjiqdXshvp2g0HbPzzQWHENiwFnhKpDD0OTWzl omBgxb949QJpwJ3wLaovTF3F27dJ+D+S7vspV5If2+GqxNvfqstFEVH2 X-Gm-Gg: ATEYQzw1k74OGoEUJKjn3wTfDiEinde3VbJ3yt9brnF1XosXSH09AC1h5YwrGAeVmPq FDYggfgjrZcrG90Iki2b67U5CkeFqfH6pS+uV2kWn2w9S+CSpjD9Lu3ZXimfAZYWJ3bnS/X4TPa KsUgPfLYs5Z5wAWgCJ6gO2gqRC+WOGqRmXnXYwFAg2LwQZtORNq5L3AltD0O6Hnd9OliaCvnMJW +P/8PvksfOa/5rUk/wOw0nUiKSxewE1XTAU89Jw5Vttoxr4jH96sXXc7XhI9qvdavosCRtvUVKH cCnChVhLhjsXxYEtMLrYGnWHRrpGejzWBSVH/HfxBAdrRvDpLIhee5n7CAhCbgKte/qFTJg9bj6 Am0QCeGxQ+kxfPdePe/u1fwpPMD27geN19TH9E0osqeLmLGEixAnCyxkCMb00Yt3+Q05gVOs064 xODHYjbMWm3OJtCT+XA6yDYqv6gAjeFSsKAs8ett7JvwVNfdQD X-Received: by 2002:a05:6000:2584:b0:43b:4e01:4aa9 with SMTP id ffacd0b85a97d-43b64242a6emr1209662f8f.10.1773951938920; Thu, 19 Mar 2026 13:25:38 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.37 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:38 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 22/55] drivers: hv: dxgkrnl: Ioctl to put device to error state Date: Thu, 19 Mar 2026 20:24:36 +0000 Message-ID: <20260319202509.63802-23-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement the ioctl to put the virtual compute device to the error state (LX_DXMARKDEVICEASERROR). This ioctl is used by the user mode driver when it detects an unrecoverable error condition. When a compute device is put to the error state, all subsequent ioctl calls to the device will fail. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 3 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 25 +++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 5 +++++ drivers/hv/dxgkrnl/ioctl.c | 38 ++++++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 12 +++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index dafc721ed6cf..b454c7430f06 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -856,6 +856,9 @@ int dxgvmb_send_update_alloc_property(struct dxgprocess= *process, struct d3dddi_updateallocproperty *args, struct d3dddi_updateallocproperty *__user inargs); +int dxgvmb_send_mark_device_as_error(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_markdeviceaserror *args); int dxgvmb_send_set_allocation_priority(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_setallocationpriority *a); diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 8bdd49bc7aa6..f7264b12a477 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -2730,6 +2730,31 @@ int dxgvmb_send_update_alloc_property(struct dxgproc= ess *process, return ret; } =20 +int dxgvmb_send_mark_device_as_error(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_markdeviceaserror *args) +{ + struct dxgkvmb_command_markdeviceaserror *command; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_MARKDEVICEASERROR, + process->host_handle); + command->args =3D *args; + ret =3D 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_set_allocation_priority(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_setallocationpriority *args) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index e1c2ed7b1580..a66e11097bb2 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -627,6 +627,11 @@ struct dxgkvmb_command_updateallocationproperty_return= { struct ntstatus status; }; =20 +struct dxgkvmb_command_markdeviceaserror { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_markdeviceaserror args; +}; + /* Returns ntstatus */ struct dxgkvmb_command_changevideomemoryreservation { struct dxgkvmb_command_vgpu_to_host hdr; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 78de76abce2d..ce4af610ada7 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3341,6 +3341,42 @@ dxgkio_update_alloc_property(struct dxgprocess *proc= ess, void *__user inargs) return ret; } =20 +static int +dxgkio_mark_device_as_error(struct dxgprocess *process, void *__user inarg= s) +{ + struct d3dkmt_markdeviceaserror args; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + device->execution_state =3D _D3DKMT_DEVICEEXECUTION_RESET; + ret =3D dxgvmb_send_mark_device_as_error(process, adapter, &args); +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_query_alloc_residency(struct dxgprocess *process, void *__user inar= gs) { @@ -4404,7 +4440,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x23 */ {}, /* 0x24 */ {}, /* 0x25 */ {dxgkio_lock2, LX_DXLOCK2}, -/* 0x26 */ {}, +/* 0x26 */ {dxgkio_mark_device_as_error, LX_DXMARKDEVICEASERROR}, /* 0x27 */ {}, /* 0x28 */ {}, /* 0x29 */ {}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 749edf28bd43..ce5a638a886d 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -790,6 +790,16 @@ struct d3dkmt_unlock2 { struct d3dkmthandle allocation; }; =20 +enum d3dkmt_device_error_reason { + _D3DKMT_DEVICE_ERROR_REASON_GENERIC =3D 0x80000000, + _D3DKMT_DEVICE_ERROR_REASON_DRIVER_ERROR =3D 0x80000006, +}; + +struct d3dkmt_markdeviceaserror { + struct d3dkmthandle device; + enum d3dkmt_device_error_reason reason; +}; + enum d3dkmt_standardallocationtype { _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP =3D 1, _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER =3D 2, @@ -1290,6 +1300,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions) #define LX_DXLOCK2 \ _IOWR(0x47, 0x25, struct d3dkmt_lock2) +#define LX_DXMARKDEVICEASERROR \ + _IOWR(0x47, 0x26, struct d3dkmt_markdeviceaserror) #define LX_DXQUERYALLOCATIONRESIDENCY \ _IOWR(0x47, 0x2a, struct d3dkmt_queryallocationresidency) #define LX_DXSETALLOCATIONPRIORITY \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 349E03FADFD for ; Thu, 19 Mar 2026 20:25:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951945; cv=none; b=HkSDsSTaNaD14UIEdmqCixYPbVKOgkXOswY6mal55skY12scQz4ZABlARNMRMu3Bx5NiRZV8ZSv+HWjCSfDKmD84ifd+0fEjQ4XU8UGK1omMvPRdE3XMy21BkpgFAB63vzLPLqiHxtFqQK7c4u5U+0FP0CbEZz8M7PL4poB/wW0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951945; c=relaxed/simple; bh=cTHMrhLFBJpZSrHBJN9rBbXEZ9RqxyfSw9KSRCI/12c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tHE2jyS4JbRII42FGn9DflybAxF/kIkWJ65/TPuuvm2cYmuBZR5d/AV9IXbdQaspz7XiXSZca34YSUnHsXn/VASjtiYCJuECkIiz/SS/bcttADubjxZX7qcJr05PTFYrqPnLjpe2SJQthUno6iMszl3MG1SqAyAbX+KxcQ/Zvsc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=eBhpYbMt; arc=none smtp.client-ip=209.85.221.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eBhpYbMt" Received: by mail-wr1-f42.google.com with SMTP id ffacd0b85a97d-43b4d734678so1373002f8f.1 for ; Thu, 19 Mar 2026 13:25:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951940; x=1774556740; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ItlcFlAFNUK9iEL+O6oBAG3ZQTT/S5ep55yAMkx91hI=; b=eBhpYbMt77jPeDCqLa/DYL/PjikezLVRpAf8ERX6k1bbmw51OCPJka+lNXxkk4623U 1gem5Dm2fG5//4x5gNuq/E2Xpcw9+epflfHW4mY7vLuM7ah221yfU4lfv2qQd2rILqSe Bht5BU49yfZLGMvhczUdv6N7zNU8jOwBMxmxaz5TBfnvDNiXcg9GRA+oar0DnGVmbN+4 Jrz+1o4YrimhE5V0WJ0TF4qbYTC75tOhKHC8T1apMYRHIVSBwoyKgWJD0eS07U1Fbo8O /634Icoe58yap9kfgwl0G61n+n/xZ6w8+ZtNddOtD9/jifINsHSTRWJv5sSwKjH/Q+Qp +KdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951940; x=1774556740; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ItlcFlAFNUK9iEL+O6oBAG3ZQTT/S5ep55yAMkx91hI=; b=GhNlddzkdh0rKQBhprrlKnd9jVYGdj4nf10ZgkX9UVOxwbteSVyWv5KT5dKEjP1/zz cVZ/+vPUS3WVwMwYS9EYxmyHD3m4Dfvxd+3G4LWzi71SDfUcpqpMWWrVXEdKq+9Vwlg3 xSu5108MERWREBNLecbRlL3Z1oImr0G81kJD88QWNfItNuX0MLIGFYZSxzyIyWN9+hg8 zjh17N+gDJz+mNciAxtYCQv/5DscG9TkJw1KQNpBP7rkaYaF6cBfl0yMwy45nIc2ZlG7 hblPnVwYSn9oNUxtm71Cc/JHHEOTEJegfUYtlsM4clPKvwMPiA1dhMdzId8sfxrw2PLf Fbfg== X-Gm-Message-State: AOJu0YxYBjVivAbfCqUSEedx0o3q9IVXnEXbrvgp/+p7ul8CQuQNYyKb jJuSHIQjsVtTWu5scup47m61zNxMvasHVVNtPTiyAykUSDVoGM5RUVnc X-Gm-Gg: ATEYQzy0mcgXDaT9fHbi9fXglCOrgLniT+lpQUCDzrGPjG4d3CDYp5uNIAW4ifWBNTy ecFj1ay5GOirxuZVvvS+XEYBBjyokfs8ApMZ7FkMTBzu0cndQf+SjDQ4dbjnSwcx9y2LP6Ia47x yVgPo2//dxKYdYOXbpTgMlVOyQCdB9/ew3XXvB9qAzVe0+Gz79W8+x2uZxv+lfdNKx05Ej8iL46 ga4rAtyiYIFWxBLRXFJaSc2TcVlN3gJ5cQl8Y/9FJgNl/HVWj50dWLw0uJQQcqDNqgdQubLkoO4 6ToT6AgbZSNbsxPg5PQ7qFpNJmse1sIfwAO3b0xN18TFucgZDLLZ4+DYL2hUWpsKnwmM+CJjFfz pto7fB7WLYF5AVxgus8bPWyfTzbBhYyO6IXmlpE82oviL1YOzHu0Cdz9qFsnT34L8aJvRZlevf4 BZBjQsBd8BR6ReJVfE0sloi34ynQF210oYV7t9HWrOWU3waTm3f35FEUfhqT8= X-Received: by 2002:a05:6000:26c3:b0:43b:45d1:f438 with SMTP id ffacd0b85a97d-43b64234722mr1193145f8f.3.1773951940150; Thu, 19 Mar 2026 13:25:40 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.39 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:39 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 23/55] drivers: hv: dxgkrnl: Ioctls to query statistics and clock calibration Date: Thu, 19 Mar 2026 20:24:37 +0000 Message-ID: <20260319202509.63802-24-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls to query statistics from the VGPU device (LX_DXQUERYSTATISTICS) and to query clock calibration (LX_DXQUERYCLOCKCALIBRATION). The LX_DXQUERYSTATISTICS ioctl is used to query various statistics from the compute device on the host. The LX_DXQUERYCLOCKCALIBRATION ioctl queries the compute device clock and is used for performance monitoring. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 8 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 77 +++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 21 +++++++ drivers/hv/dxgkrnl/ioctl.c | 111 +++++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 62 +++++++++++++++++++ 5 files changed, 277 insertions(+), 2 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index b454c7430f06..a55873bdd9a6 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -885,6 +885,11 @@ int dxgvmb_send_query_adapter_info(struct dxgprocess *= process, int dxgvmb_send_submit_command_hwqueue(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_submitcommandtohwqueue *a); +int dxgvmb_send_query_clock_calibration(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryclockcalibration *a, + struct d3dkmt_queryclockcalibration + *__user inargs); int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_flushheaptransitions *arg); @@ -929,6 +934,9 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *dev= ice, void *prive_alloc_data, u32 *res_priv_data_size, void *priv_res_data); +int dxgvmb_send_query_statistics(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_querystatistics *args); int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel, void *command, u32 cmd_size); diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index f7264b12a477..9a1864bb4e14 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1829,6 +1829,48 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess= *process, return ret; } =20 +int dxgvmb_send_query_clock_calibration(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_queryclockcalibration + *args, + struct d3dkmt_queryclockcalibration + *__user inargs) +{ + struct dxgkvmb_command_queryclockcalibration *command; + struct dxgkvmb_command_queryclockcalibration_return result; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION, + process->host_handle); + command->args =3D *args; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret < 0) + goto cleanup; + ret =3D copy_to_user(&inargs->clock_data, &result.clock_data, + sizeof(result.clock_data)); + if (ret) { + pr_err("%s failed to copy clock data", __func__); + ret =3D -EINVAL; + goto cleanup; + } + ret =3D ntstatus2int(result.status); + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_flush_heap_transitions(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_flushheaptransitions *args) @@ -3242,3 +3284,38 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgpro= cess *process, return ret; } =20 +int dxgvmb_send_query_statistics(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_querystatistics *args) +{ + struct dxgkvmb_command_querystatistics *command; + struct dxgkvmb_command_querystatistics_return *result; + int ret; + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; + + ret =3D init_message_res(&msg, adapter, process, sizeof(*command), + sizeof(*result)); + if (ret) + goto cleanup; + command =3D msg.msg; + result =3D msg.res; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_QUERYSTATISTICS, + process->host_handle); + command->args =3D *args; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + result, msg.res_size); + if (ret < 0) + goto cleanup; + + args->result =3D result->result; + ret =3D ntstatus2int(result->status); + +cleanup: + free_message((struct dxgvmbusmsg *)&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index a66e11097bb2..17768ed0e68d 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -372,6 +372,16 @@ struct dxgkvmb_command_flushheaptransitions { struct dxgkvmb_command_vgpu_to_host hdr; }; =20 +struct dxgkvmb_command_queryclockcalibration { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_queryclockcalibration args; +}; + +struct dxgkvmb_command_queryclockcalibration_return { + struct ntstatus status; + struct dxgk_gpuclockdata clock_data; +}; + struct dxgkvmb_command_createallocation_allocinfo { u32 flags; u32 priv_drv_data_size; @@ -408,6 +418,17 @@ struct dxgkvmb_command_openresource_return { /* struct d3dkmthandle allocation[allocation_count]; */ }; =20 +struct dxgkvmb_command_querystatistics { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmt_querystatistics args; +}; + +struct dxgkvmb_command_querystatistics_return { + struct ntstatus status; + u32 reserved; + struct d3dkmt_querystatistics_result result; +}; + struct dxgkvmb_command_getstandardallocprivdata { struct dxgkvmb_command_vgpu_to_host hdr; enum d3dkmdt_standardallocationtype alloc_type; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index ce4af610ada7..4babb21f38a9 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -149,6 +149,65 @@ static int dxgkio_open_adapter_from_luid(struct dxgpro= cess *process, return ret; } =20 +static int dxgkio_query_statistics(struct dxgprocess *process, + void __user *inargs) +{ + struct d3dkmt_querystatistics *args; + int ret; + struct dxgadapter *entry; + struct dxgadapter *adapter =3D NULL; + struct winluid tmp; + struct dxgglobal *dxgglobal =3D dxggbl(); + + args =3D vzalloc(sizeof(struct d3dkmt_querystatistics)); + if (args =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + + ret =3D copy_from_user(args, inargs, sizeof(*args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED); + list_for_each_entry(entry, &dxgglobal->adapter_list_head, + adapter_list_entry) { + if (dxgadapter_acquire_lock_shared(entry) =3D=3D 0) { + if (*(u64 *) &entry->luid =3D=3D + *(u64 *) &args->adapter_luid) { + adapter =3D entry; + break; + } + dxgadapter_release_lock_shared(entry); + } + } + dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED); + if (adapter) { + tmp =3D args->adapter_luid; + args->adapter_luid =3D adapter->host_adapter_luid; + ret =3D dxgvmb_send_query_statistics(process, adapter, args); + if (ret >=3D 0) { + args->adapter_luid =3D tmp; + ret =3D copy_to_user(inargs, args, sizeof(*args)); + if (ret) { + DXG_ERR("failed to copy args"); + ret =3D -EINVAL; + } + } + dxgadapter_release_lock_shared(adapter); + } + +cleanup: + if (args) + vfree(args); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkp_enum_adapters(struct dxgprocess *process, union d3dkmt_enumadapters_filter filter, @@ -3536,6 +3595,54 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *= process, void *__user inargs return ret; } =20 +static int +dxgkio_query_clock_calibration(struct dxgprocess *process, void *__user in= args) +{ + struct d3dkmt_queryclockcalibration args; + int ret; + struct dxgadapter *adapter =3D NULL; + bool adapter_locked =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + adapter_locked =3D true; + + args.adapter =3D adapter->host_handle; + ret =3D dxgvmb_send_query_clock_calibration(process, adapter, + &args, inargs); + if (ret < 0) + goto cleanup; + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy output args"); + ret =3D -EINVAL; + } + +cleanup: + + if (adapter_locked) + dxgadapter_release_lock_shared(adapter); + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + return ret; +} + static int dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user ina= rgs) { @@ -4470,14 +4577,14 @@ static struct ioctl_desc ioctls[] =3D { /* 0x3b */ {dxgkio_wait_sync_object_gpu, LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU}, /* 0x3c */ {dxgkio_get_allocation_priority, LX_DXGETALLOCATIONPRIORITY}, -/* 0x3d */ {}, +/* 0x3d */ {dxgkio_query_clock_calibration, LX_DXQUERYCLOCKCALIBRATION}, /* 0x3e */ {dxgkio_enum_adapters3, LX_DXENUMADAPTERS3}, /* 0x3f */ {dxgkio_share_objects, LX_DXSHAREOBJECTS}, /* 0x40 */ {dxgkio_open_sync_object_nt, LX_DXOPENSYNCOBJECTFROMNTHANDLE2}, /* 0x41 */ {dxgkio_query_resource_info_nt, LX_DXQUERYRESOURCEINFOFROMNTHANDLE}, /* 0x42 */ {dxgkio_open_resource_nt, LX_DXOPENRESOURCEFROMNTHANDLE}, -/* 0x43 */ {}, +/* 0x43 */ {dxgkio_query_statistics, LX_DXQUERYSTATISTICS}, /* 0x44 */ {dxgkio_share_object_with_host, LX_DXSHAREOBJECTWITHHOST}, /* 0x45 */ {}, }; diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index ce5a638a886d..ea18242ceb83 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -996,6 +996,34 @@ struct d3dkmt_queryadapterinfo { __u32 private_data_size; }; =20 +#pragma pack(push, 1) + +struct dxgk_gpuclockdata_flags { + union { + struct { + __u32 context_management_processor:1; + __u32 reserved:31; + }; + __u32 value; + }; +}; + +struct dxgk_gpuclockdata { + __u64 gpu_frequency; + __u64 gpu_clock_counter; + __u64 cpu_clock_counter; + struct dxgk_gpuclockdata_flags flags; +} __packed; + +struct d3dkmt_queryclockcalibration { + struct d3dkmthandle adapter; + __u32 node_ordinal; + __u32 physical_adapter_index; + struct dxgk_gpuclockdata clock_data; +}; + +#pragma pack(pop) + struct d3dkmt_flushheaptransitions { struct d3dkmthandle adapter; }; @@ -1238,6 +1266,36 @@ struct d3dkmt_enumadapters3 { #endif }; =20 +enum d3dkmt_querystatistics_type { + _D3DKMT_QUERYSTATISTICS_ADAPTER =3D 0, + _D3DKMT_QUERYSTATISTICS_PROCESS =3D 1, + _D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER =3D 2, + _D3DKMT_QUERYSTATISTICS_SEGMENT =3D 3, + _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT =3D 4, + _D3DKMT_QUERYSTATISTICS_NODE =3D 5, + _D3DKMT_QUERYSTATISTICS_PROCESS_NODE =3D 6, + _D3DKMT_QUERYSTATISTICS_VIDPNSOURCE =3D 7, + _D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE =3D 8, + _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP =3D 9, + _D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER =3D 10, +}; + +struct d3dkmt_querystatistics_result { + char size[0x308]; +}; + +struct d3dkmt_querystatistics { + union { + struct { + enum d3dkmt_querystatistics_type type; + struct winluid adapter_luid; + __u64 process; + struct d3dkmt_querystatistics_result result; + }; + char size[0x328]; + }; +}; + struct d3dkmt_shareobjectwithhost { struct d3dkmthandle device_handle; struct d3dkmthandle object_handle; @@ -1328,6 +1386,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x3b, struct d3dkmt_waitforsynchronizationobjectfromgpu) #define LX_DXGETALLOCATIONPRIORITY \ _IOWR(0x47, 0x3c, struct d3dkmt_getallocationpriority) +#define LX_DXQUERYCLOCKCALIBRATION \ + _IOWR(0x47, 0x3d, struct d3dkmt_queryclockcalibration) #define LX_DXENUMADAPTERS3 \ _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3) #define LX_DXSHAREOBJECTS \ @@ -1338,6 +1398,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x41, struct d3dkmt_queryresourceinfofromnthandle) #define LX_DXOPENRESOURCEFROMNTHANDLE \ _IOWR(0x47, 0x42, struct d3dkmt_openresourcefromnthandle) +#define LX_DXQUERYSTATISTICS \ + _IOWR(0x47, 0x43, struct d3dkmt_querystatistics) #define LX_DXSHAREOBJECTWITHHOST \ _IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost) From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 20DD83FAE0B for ; Thu, 19 Mar 2026 20:25:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951946; cv=none; b=FwbYn3oy+SU+GKPz/cAlRT9aWbhekCCC9PP9qljM7roHJyiFPz3acwgilUbCydrsVYzzQv3AiLm3TkjeQi20EqJTAWiAo2Z5sEvmjZTh7P6KYt7meWi/PFZYRWo26vbKFgdX9XxsqrjTpI5HYOolqhQn7MANChsgdVHnMtBqF0g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951946; c=relaxed/simple; bh=fEmYhkE9WL70ZTMxqR85nM8bi6WT0ZLiYvejlpetuSE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Jp6esYuKifE5JLrdYnLTTtVBB/Uuf24hOaIydqDOl9UIL2K5e9TVas3qhMD0ZCc+3pnAGufAr8yFdISfz8ea1jqNZVIOZxgbDmSUvh2w2iSdcYzEfN9qGCGYvsG9dUiTjL7Hpn7GCobnue3BrkSkKYwW2Wm3TYAeyvc1x7Spasw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FZkqHL2B; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FZkqHL2B" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-439b9b1900bso859040f8f.1 for ; Thu, 19 Mar 2026 13:25:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951941; x=1774556741; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XKsBdugocoQmJoY++9YCzacKrwO/Pe+LkVEnylf4tv8=; b=FZkqHL2Bymvztggk2Nk5qJfDw7HW8Mvtj2nnQ5rQPj8bTkGdTCU2FTEGG/U9tSGGQY 20U/xFuLRTd5Qw8FkSHPYJNz2tcYk87lvuFrmkEhQSeGZW8y8+tobKCcGfOaEbxb2cwQ 36cc7gjXpyoduDAKF8GeWg5NmkDMhemoGwt5hH1ESbbNE+8mBneUCh6kyxQkLN5JKqJv qaF91dfA5SSUNwqnmFXT/VGz9Pgn4sHMw9rynScLMl2Lfp3cJH/NIpi/y5CKWFaVZ1B1 hwbqh3zFj9dTU9+e/jqZK9yAJEDyhfhEmMoNxJD24oeTX1rlcFjyC9j6WQYMFcTQBXvi 8QVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951941; x=1774556741; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=XKsBdugocoQmJoY++9YCzacKrwO/Pe+LkVEnylf4tv8=; b=ayijf4HAdMI2Tf1iX8ivDQxT7AkRr1VBQ25Qktbhn9cBraFvk7F/aEpSjPKIVrOpqE rNMnhU6t3Lcfnm35iRGPefyeOQmi6oAiTbp12wJZYu6BYqnjb32CYlU7uDvuNe3I0hQF Oe3B4kiVrPLZdo4AljaT1p92/p1gocXI+F01qt/d2+60/g8Z3ZAU6XCE6mqT6kk4NedT bLtYqX4CNA0DFNZftGWJbCR5J3vvmvDUzzRgDtkqfxgFpNp+BP90oIroUw7lqqQNlnzF e074yUHqmUClnH2eRZX35B58zA12yG/C2u9ny0WnL2eevUkpi8BW1bgOxPZ/7QIt00lP oV0w== X-Gm-Message-State: AOJu0Yx4eU5aqMK6/iLmEsUaALC8W2wtIDYqsCw6QyK8MxB1d+mg446Q 6vqxw5Icj5sjuy412ZLcb9TicZEHgsKBg+rTfHmhNBbpUrqthOSJ6/7C X-Gm-Gg: ATEYQzw+aTXoVIq40A8qzFdwKQqDy4nn1l0GBSBzs0rDFPJKZTU3pROg4YZpuXXw0dj /HbyMzT9dJYkf794hci/hIPYDvCb22NOdaOWNxQuua+vf9OLz476ZQPcviXWuHV2zQdL0+iJreM EKJiCEXFKhzHDyCjQ/9pIUNJsIxIwppporDy1UKiPGwIIl4VgBbROuM8sVn6nSBIbj3HmM8315a w4TYX8qDqqXIMXrNIGqHRo8zYLe3eppaJPG7HNTl6FyzQvqdFXe4PelV/sM4a3pjcYMOLUv/TWl 2t0bp9nJA4JWIOWrfyB63NgKIxZThH6xVTisXdEtJbht9AsVuEqDgSUZvw4ChdDk1bNqxVK2Dtj QbRgyzmMtSYlBx10eI/JteSEWg2s3sExEpPTsvBy8hwbXH1oLkkNPPsIENqEK6EG1CMTppvC5i4 JqNR3aj7NVhwGRIAWp5eW+WQWdSWoVOlZQ4WWwKTzdGQ1Xn0xA X-Received: by 2002:a5d:588f:0:b0:439:b3a3:7239 with SMTP id ffacd0b85a97d-43b6423fb3dmr1306490f8f.5.1773951941251; Thu, 19 Mar 2026 13:25:41 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.40 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:40 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 24/55] drivers: hv: dxgkrnl: Offer and reclaim allocations Date: Thu, 19 Mar 2026 20:24:38 +0000 Message-ID: <20260319202509.63802-25-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement ioctls to offer and reclaim compute device allocations: - LX_DXOFFERALLOCATIONS, - LX_DXRECLAIMALLOCATIONS2 When a user mode driver (UMD) does not need to access an allocation, it can "offer" it by issuing the LX_DXOFFERALLOCATIONS ioctl. This means that the allocation is not in use and its local device memory could be evicted. The freed space could be given to another allocation. When the allocation is again needed, the UMD can attempt to"reclaim" the allocation by issuing the LX_DXRECLAIMALLOCATIONS2 ioctl. If the allocation is still not evicted, the reclaim operation succeeds and no other action is required. If the reclaim operation fails, the caller must restore the content of the allocation before it can be used by the device. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 8 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 124 +++++++++++++++++++++++++++++++++- drivers/hv/dxgkrnl/dxgvmbus.h | 27 ++++++++ drivers/hv/dxgkrnl/ioctl.c | 117 +++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 67 ++++++++++++++++++ 5 files changed, 340 insertions(+), 3 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index a55873bdd9a6..494ea8fb0bb3 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -865,6 +865,14 @@ int dxgvmb_send_set_allocation_priority(struct dxgproc= ess *process, int dxgvmb_send_get_allocation_priority(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_getallocationpriority *a); +int dxgvmb_send_offer_allocations(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_offerallocations *args); +int dxgvmb_send_reclaim_allocations(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle device, + struct d3dkmt_reclaimallocations2 *args, + u64 __user *paging_fence_value); int dxgvmb_send_change_vidmem_reservation(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmthandle other_process, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 9a1864bb4e14..8448fd78975b 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1858,7 +1858,7 @@ int dxgvmb_send_query_clock_calibration(struct dxgpro= cess *process, ret =3D copy_to_user(&inargs->clock_data, &result.clock_data, sizeof(result.clock_data)); if (ret) { - pr_err("%s failed to copy clock data", __func__); + DXG_ERR("failed to copy clock data"); ret =3D -EINVAL; goto cleanup; } @@ -2949,6 +2949,128 @@ int dxgvmb_send_get_allocation_priority(struct dxgp= rocess *process, return ret; } =20 +int dxgvmb_send_offer_allocations(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_offerallocations *args) +{ + struct dxgkvmb_command_offerallocations *command; + int ret =3D -EINVAL; + u32 alloc_size =3D sizeof(struct d3dkmthandle) * args->allocation_count; + u32 cmd_size =3D sizeof(struct dxgkvmb_command_offerallocations) + + alloc_size - sizeof(struct d3dkmthandle); + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_OFFERALLOCATIONS, + process->host_handle); + command->flags =3D args->flags; + command->priority =3D args->priority; + command->device =3D args->device; + command->allocation_count =3D args->allocation_count; + if (args->resources) { + command->resources =3D true; + ret =3D copy_from_user(command->allocations, args->resources, + alloc_size); + } else { + ret =3D copy_from_user(command->allocations, + args->allocations, alloc_size); + } + if (ret) { + DXG_ERR("failed to copy input handles"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); + +cleanup: + free_message(&msg, process); + if (ret) + pr_debug("err: %s %d", __func__, ret); + return ret; +} + +int dxgvmb_send_reclaim_allocations(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle device, + struct d3dkmt_reclaimallocations2 *args, + u64 __user *paging_fence_value) +{ + struct dxgkvmb_command_reclaimallocations *command; + struct dxgkvmb_command_reclaimallocations_return *result; + int ret; + u32 alloc_size =3D sizeof(struct d3dkmthandle) * args->allocation_count; + u32 cmd_size =3D sizeof(struct dxgkvmb_command_reclaimallocations) + + alloc_size - sizeof(struct d3dkmthandle); + u32 result_size =3D sizeof(*result); + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; + + if (args->results) + result_size +=3D (args->allocation_count - 1) * + sizeof(enum d3dddi_reclaim_result); + + ret =3D init_message_res(&msg, adapter, process, cmd_size, result_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + result =3D msg.res; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_RECLAIMALLOCATIONS, + process->host_handle); + command->device =3D device; + command->paging_queue =3D args->paging_queue; + command->allocation_count =3D args->allocation_count; + command->write_results =3D args->results !=3D NULL; + if (args->resources) { + command->resources =3D true; + ret =3D copy_from_user(command->allocations, args->resources, + alloc_size); + } else { + ret =3D copy_from_user(command->allocations, + args->allocations, alloc_size); + } + if (ret) { + DXG_ERR("failed to copy input handles"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + result, msg.res_size); + if (ret < 0) + goto cleanup; + ret =3D copy_to_user(paging_fence_value, + &result->paging_fence_value, sizeof(u64)); + if (ret) { + DXG_ERR("failed to copy paging fence"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D ntstatus2int(result->status); + if (NT_SUCCESS(result->status) && args->results) { + ret =3D copy_to_user(args->results, result->discarded, + sizeof(result->discarded[0]) * + args->allocation_count); + if (ret) { + DXG_ERR("failed to copy results"); + ret =3D -EINVAL; + } + } + +cleanup: + free_message((struct dxgvmbusmsg *)&msg, process); + if (ret) + pr_debug("err: %s %d", __func__, ret); + return ret; +} + int dxgvmb_send_change_vidmem_reservation(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmthandle other_process, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 17768ed0e68d..558c6576a262 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -653,6 +653,33 @@ struct dxgkvmb_command_markdeviceaserror { struct d3dkmt_markdeviceaserror args; }; =20 +/* Returns ntstatus */ +struct dxgkvmb_command_offerallocations { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + u32 allocation_count; + enum d3dkmt_offer_priority priority; + struct d3dkmt_offer_flags flags; + bool resources; + struct d3dkmthandle allocations[1]; +}; + +struct dxgkvmb_command_reclaimallocations { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle device; + struct d3dkmthandle paging_queue; + u32 allocation_count; + bool resources; + bool write_results; + struct d3dkmthandle allocations[1]; +}; + +struct dxgkvmb_command_reclaimallocations_return { + u64 paging_fence_value; + struct ntstatus status; + enum d3dddi_reclaim_result discarded[1]; +}; + /* Returns ntstatus */ struct dxgkvmb_command_changevideomemoryreservation { struct dxgkvmb_command_vgpu_to_host hdr; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index 4babb21f38a9..fa880aa0196a 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -1961,6 +1961,119 @@ dxgkio_destroy_allocation(struct dxgprocess *proces= s, void *__user inargs) return ret; } =20 +static int +dxgkio_offer_allocations(struct dxgprocess *process, void *__user inargs) +{ + int ret; + struct d3dkmt_offerallocations args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.allocation_count > D3DKMT_MAKERESIDENT_ALLOC_MAX || + args.allocation_count =3D=3D 0) { + DXG_ERR("invalid number of allocations"); + ret =3D -EINVAL; + goto cleanup; + } + + if ((args.resources =3D=3D NULL) =3D=3D (args.allocations =3D=3D NULL)) { + DXG_ERR("invalid pointer to resources/allocations"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_offer_allocations(process, adapter, &args); + +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_reclaim_allocations(struct dxgprocess *process, void *__user inargs) +{ + int ret; + struct d3dkmt_reclaimallocations2 args; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dkmt_reclaimallocations2 * __user in_args =3D inargs; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.allocation_count > D3DKMT_MAKERESIDENT_ALLOC_MAX || + args.allocation_count =3D=3D 0) { + DXG_ERR("invalid number of allocations"); + ret =3D -EINVAL; + goto cleanup; + } + + if ((args.resources =3D=3D NULL) =3D=3D (args.allocations =3D=3D NULL)) { + DXG_ERR("invalid pointer to resources/allocations"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + args.paging_queue); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_reclaim_allocations(process, adapter, + device->handle, &args, + &in_args->paging_fence_value); + +cleanup: + + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_submit_command(struct dxgprocess *process, void *__user inargs) { @@ -4548,12 +4661,12 @@ static struct ioctl_desc ioctls[] =3D { /* 0x24 */ {}, /* 0x25 */ {dxgkio_lock2, LX_DXLOCK2}, /* 0x26 */ {dxgkio_mark_device_as_error, LX_DXMARKDEVICEASERROR}, -/* 0x27 */ {}, +/* 0x27 */ {dxgkio_offer_allocations, LX_DXOFFERALLOCATIONS}, /* 0x28 */ {}, /* 0x29 */ {}, /* 0x2a */ {dxgkio_query_alloc_residency, LX_DXQUERYALLOCATIONRESIDENCY}, /* 0x2b */ {}, -/* 0x2c */ {}, +/* 0x2c */ {dxgkio_reclaim_allocations, LX_DXRECLAIMALLOCATIONS2}, /* 0x2d */ {}, /* 0x2e */ {dxgkio_set_allocation_priority, LX_DXSETALLOCATIONPRIORITY}, /* 0x2f */ {}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index ea18242ceb83..46b9f6d303bf 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -61,6 +61,7 @@ struct winluid { #define D3DDDI_MAX_WRITTEN_PRIMARIES 16 =20 #define D3DKMT_CREATEALLOCATION_MAX 1024 +#define D3DKMT_MAKERESIDENT_ALLOC_MAX (1024 * 10) #define D3DKMT_ADAPTERS_MAX 64 #define D3DDDI_MAX_BROADCAST_CONTEXT 64 #define D3DDDI_MAX_OBJECT_WAITED_ON 32 @@ -1087,6 +1088,68 @@ struct d3dddi_updateallocproperty { }; }; =20 +enum d3dkmt_offer_priority { + _D3DKMT_OFFER_PRIORITY_LOW =3D 1, + _D3DKMT_OFFER_PRIORITY_NORMAL =3D 2, + _D3DKMT_OFFER_PRIORITY_HIGH =3D 3, + _D3DKMT_OFFER_PRIORITY_AUTO =3D 4, +}; + +struct d3dkmt_offer_flags { + union { + struct { + __u32 offer_immediately:1; + __u32 allow_decommit:1; + __u32 reserved:30; + }; + __u32 value; + }; +}; + +struct d3dkmt_offerallocations { + struct d3dkmthandle device; + __u32 reserved; +#ifdef __KERNEL__ + struct d3dkmthandle *resources; + const struct d3dkmthandle *allocations; +#else + __u64 resources; + __u64 allocations; +#endif + __u32 allocation_count; + enum d3dkmt_offer_priority priority; + struct d3dkmt_offer_flags flags; + __u32 reserved1; +}; + +enum d3dddi_reclaim_result { + _D3DDDI_RECLAIM_RESULT_OK =3D 0, + _D3DDDI_RECLAIM_RESULT_DISCARDED =3D 1, + _D3DDDI_RECLAIM_RESULT_NOT_COMMITTED =3D 2, +}; + +struct d3dkmt_reclaimallocations2 { + struct d3dkmthandle paging_queue; + __u32 allocation_count; +#ifdef __KERNEL__ + struct d3dkmthandle *resources; + struct d3dkmthandle *allocations; +#else + __u64 resources; + __u64 allocations; +#endif + union { +#ifdef __KERNEL__ + __u32 *discarded; + enum d3dddi_reclaim_result *results; +#else + __u64 discarded; + __u64 results; +#endif + }; + __u64 paging_fence_value; +}; + struct d3dkmt_changevideomemoryreservation { __u64 process; struct d3dkmthandle adapter; @@ -1360,8 +1423,12 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x25, struct d3dkmt_lock2) #define LX_DXMARKDEVICEASERROR \ _IOWR(0x47, 0x26, struct d3dkmt_markdeviceaserror) +#define LX_DXOFFERALLOCATIONS \ + _IOWR(0x47, 0x27, struct d3dkmt_offerallocations) #define LX_DXQUERYALLOCATIONRESIDENCY \ _IOWR(0x47, 0x2a, struct d3dkmt_queryallocationresidency) +#define LX_DXRECLAIMALLOCATIONS2 \ + _IOWR(0x47, 0x2c, struct d3dkmt_reclaimallocations2) #define LX_DXSETALLOCATIONPRIORITY \ _IOWR(0x47, 0x2e, struct d3dkmt_setallocationpriority) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 440773FB040 for ; Thu, 19 Mar 2026 20:25:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951949; cv=none; b=lgdNLh/tx0wl+s8d+1b0v9bB+O3h0Rb37ghctjJglWhpvIH+4wjDP8VYq8g2a+0HSQR3ajSiDrXZTi8YvOJGiQbFNh2Shh2eoGyrXZbqaihtaFKo+2X1GEHpV6eupelBbzg8XBYwATF8SA1+dq/6jX6aYa3AyD2vmeynY02WrVk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951949; c=relaxed/simple; bh=g4L+OyJnGZxRY1AKRn2XRN83HmJ0OAzYwZNM3pOegCQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QGxr5vxUUvMcJMS2Mt5qRvb24tZ7XJO2mQJh4MJgYDUVTPpgi477IWBm5eYS0RdtSzdIpnSihG+MuBGoVOJGJPn2fs7t6SPxZTJuN/ey0gI7qaemapn3xJ1uGV95H/yTo4IG8B0tL88wmwRBK47UWQsOMvNRYVFZYQ2VkpoDLt4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=MPjnLyUi; arc=none smtp.client-ip=209.85.221.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="MPjnLyUi" Received: by mail-wr1-f50.google.com with SMTP id ffacd0b85a97d-43b527ac5d0so668763f8f.2 for ; Thu, 19 Mar 2026 13:25:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951942; x=1774556742; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=AE4eBljE5ZE2/a2micJBTWEOpKIwWswMpcHBB41Pl6s=; b=MPjnLyUi6kf4mH98ayOY1grvlv6E5inow0ECZL7MQAO+cGHuaAmeW3YuxZDqfimU9Y D98/IE4AjH1LleYL3vkDehg9Eb/T5d+WpBgj3IuyDO39oLuleK08F+8gnNYwMNNyVZN7 T1QPzOH2VRKHLaAAXK5y/q9EKMv8wIAVhw++DNCeC/oOkSAOTZbxstVWuWSopUZ4yc+T 8NQBd3zVHFkYA00jbq5jD8S2LgMP/3PhyncpqF3Qk9gNfEUpCGr4PZPkN+ZkrPH0VWnb z/uUvMoPNe91uoDyT74jj3vEZRZZSac0queH24k2Cqo6jJ19PLhKRSkf1Ta3H/COt9y+ fZ8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951942; x=1774556742; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=AE4eBljE5ZE2/a2micJBTWEOpKIwWswMpcHBB41Pl6s=; b=d5OqMgjTsn2Yq4davsT3shNpdD0Uvr8IF4P70xg52MZbpyUineiYG3FPOLZzKbOXQF 4RNx+FbUb4SRChMn9TRrqfvS+aERb+TFbZUi9dTyRn61mIeL4ltzz0ssXG9nPFq5Tarn aQOPtq0l0Kpmd91kaX0FfKhAXaTOdHRVwUxM7rJrPyIavjWxr38w6atPciq9pSLuoBCC 6wcpHFcIHyz9T1lHfEEPBrI3DRuohdcWNjswNOvocz67H0EifnPJI1Z2aiglfRVi8FSl CdaXFEzXx04w6GL0GC/NNXCFK4vecDH1JxFP7V7kzd9mPCOi320zMJez/q+VejX0g0oA W3ZA== X-Gm-Message-State: AOJu0YxjT10CGetshYAa7q14/Dcqrbo2VVjd7dOl9WehnzzA3QGtF07b JJlIN/84ypTT0mh1eylM55mlbaPDrkbqp/wM59eDqkO5Vi+7oT9Ea4f/u/DDNdi3Kxg= X-Gm-Gg: ATEYQzzYp5u/fp3eTVZYAIWrm02TC1TkTGI/CIWOQeK6z+ax8amZ01pQHjqxQfWTHIm DTIWyLKDGmD17qfCWFyd+hdRHLXHi+wQZ4L7FBVEalCnpY5Yg4TL1ByaEoxIy3BueZDKhiVoMt5 7avf8OH4ZexXGkFC8c/OFJYrP3b7LXY15Mwgq5Bmw3s9wiZBsCBEQ2R2ugligmqwZBiVDFwn09f 7tdeZy4vfOuCfeZwI9XPGMuROHorpqwYWoY4nPu01PQE3rb/qh5TgDHpd9FfXxkMHUbfIb2datL uhEKmi2LdzA1MOwSev9F0Jw+/DjKkzFteRmeEaltf5M1th8+KnQ2T8NkNgiNhPYS5ZVV/a7Bdr1 01JtXO+JdEfbzlHIWQREhj4S7EvPLVxM8O6fR8ZeYhupJGsnTnSNd2fT7jthbPz1P/sEISN+hwI Xbhl+dzA8aA61TOfwtjXu2/2xGu3XxUjcxZgm78BE/jMaXSwJm X-Received: by 2002:a05:6000:184d:b0:43b:3bf9:e008 with SMTP id ffacd0b85a97d-43b6423f92emr1297004f8f.11.1773951942305; Thu, 19 Mar 2026 13:25:42 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.41 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:41 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 25/55] drivers: hv: dxgkrnl: Ioctls to manage scheduling priority Date: Thu, 19 Mar 2026 20:24:39 +0000 Message-ID: <20260319202509.63802-26-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement iocts to manage compute device scheduling priority: - LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY - LX_DXGETCONTEXTSCHEDULINGPRIORITY - LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY - LX_DXSETCONTEXTSCHEDULINGPRIORITY Each compute device execution context has an assigned scheduling priority. It is used by the compute device scheduler on the host to pick contexts for execution. There is a global priority and a priority within a process. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/dxgkrnl.h | 9 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 67 ++++++++++++- drivers/hv/dxgkrnl/dxgvmbus.h | 19 ++++ drivers/hv/dxgkrnl/ioctl.c | 177 +++++++++++++++++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 28 ++++++ 5 files changed, 294 insertions(+), 6 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 494ea8fb0bb3..02d10bdcc820 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -865,6 +865,15 @@ int dxgvmb_send_set_allocation_priority(struct dxgproc= ess *process, int dxgvmb_send_get_allocation_priority(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_getallocationpriority *a); +int dxgvmb_send_set_context_sch_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + int priority, bool in_process); +int dxgvmb_send_get_context_sch_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + int *priority, + bool in_process); int dxgvmb_send_offer_allocations(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_offerallocations *args); diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 8448fd78975b..9a610d48bed7 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -2949,6 +2949,69 @@ int dxgvmb_send_get_allocation_priority(struct dxgpr= ocess *process, return ret; } =20 +int dxgvmb_send_set_context_sch_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + int priority, + bool in_process) +{ + struct dxgkvmb_command_setcontextschedulingpriority2 *command; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_SETCONTEXTSCHEDULINGPRIORITY, + process->host_handle); + command->context =3D context; + command->priority =3D priority; + command->in_process =3D in_process; + ret =3D 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_get_context_sch_priority(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmthandle context, + int *priority, + bool in_process) +{ + struct dxgkvmb_command_getcontextschedulingpriority *command; + struct dxgkvmb_command_getcontextschedulingpriority_return result =3D { }; + int ret; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_GETCONTEXTSCHEDULINGPRIORITY, + process->host_handle); + command->context =3D context; + command->in_process =3D in_process; + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + &result, sizeof(result)); + if (ret >=3D 0) { + ret =3D ntstatus2int(result.status); + *priority =3D result.priority; + } +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_offer_allocations(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_offerallocations *args) @@ -2991,7 +3054,7 @@ int dxgvmb_send_offer_allocations(struct dxgprocess *= process, cleanup: free_message(&msg, process); if (ret) - pr_debug("err: %s %d", __func__, ret); + DXG_TRACE("err: %d", ret); return ret; } =20 @@ -3067,7 +3130,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess= *process, cleanup: free_message((struct dxgvmbusmsg *)&msg, process); if (ret) - pr_debug("err: %s %d", __func__, ret); + DXG_TRACE("err: %d", ret); return ret; } =20 diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 558c6576a262..509482e1f870 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -331,6 +331,25 @@ struct dxgkvmb_command_getallocationpriority_return { /* u32 priorities[allocation_count or 1]; */ }; =20 +/* Returns ntstatus */ +struct dxgkvmb_command_setcontextschedulingpriority2 { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle context; + int priority; + bool in_process; +}; + +struct dxgkvmb_command_getcontextschedulingpriority { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle context; + bool in_process; +}; + +struct dxgkvmb_command_getcontextschedulingpriority_return { + struct ntstatus status; + int priority; +}; + struct dxgkvmb_command_createdevice { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmt_createdeviceflags flags; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index fa880aa0196a..bc0adebe52ae 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3660,6 +3660,171 @@ dxgkio_get_allocation_priority(struct dxgprocess *p= rocess, void *__user inargs) return ret; } =20 +static int +set_context_scheduling_priority(struct dxgprocess *process, + struct d3dkmthandle hcontext, + int priority, bool in_process) +{ + int ret =3D 0; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + hcontext); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + ret =3D dxgvmb_send_set_context_sch_priority(process, adapter, + hcontext, priority, + in_process); + if (ret < 0) + DXG_ERR("send_set_context_scheduling_priority failed"); +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + return ret; +} + +static int +dxgkio_set_context_scheduling_priority(struct dxgprocess *process, + void *__user inargs) +{ + struct d3dkmt_setcontextschedulingpriority args; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D set_context_scheduling_priority(process, args.context, + args.priority, false); +cleanup: + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +get_context_scheduling_priority(struct dxgprocess *process, + struct d3dkmthandle hcontext, + int __user *priority, + bool in_process) +{ + int ret; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + int pri =3D 0; + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + hcontext); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + ret =3D dxgvmb_send_get_context_sch_priority(process, adapter, + hcontext, &pri, in_process); + if (ret < 0) + goto cleanup; + ret =3D copy_to_user(priority, &pri, sizeof(pri)); + if (ret) { + DXG_ERR("failed to copy priority to user"); + ret =3D -EINVAL; + } + +cleanup: + if (adapter) + dxgadapter_release_lock_shared(adapter); + if (device) + kref_put(&device->device_kref, dxgdevice_release); + + return ret; +} + +static int +dxgkio_get_context_scheduling_priority(struct dxgprocess *process, + void *__user inargs) +{ + struct d3dkmt_getcontextschedulingpriority args; + struct d3dkmt_getcontextschedulingpriority __user *input =3D inargs; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D get_context_scheduling_priority(process, args.context, + &input->priority, false); +cleanup: + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_set_context_process_scheduling_priority(struct dxgprocess *process, + void *__user inargs) +{ + struct d3dkmt_setcontextinprocessschedulingpriority args; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D set_context_scheduling_priority(process, args.context, + args.priority, true); +cleanup: + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + +static int +dxgkio_get_context_process_scheduling_priority(struct dxgprocess *process, + void __user *inargs) +{ + struct d3dkmt_getcontextinprocessschedulingpriority args; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D get_context_scheduling_priority(process, args.context, + &((struct d3dkmt_getcontextinprocessschedulingpriority *) + inargs)->priority, true); +cleanup: + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_change_vidmem_reservation(struct dxgprocess *process, void *__user = inargs) { @@ -4655,8 +4820,10 @@ static struct ioctl_desc ioctls[] =3D { /* 0x1e */ {}, /* 0x1f */ {dxgkio_flush_heap_transitions, LX_DXFLUSHHEAPTRANSITIONS}, /* 0x20 */ {}, -/* 0x21 */ {}, -/* 0x22 */ {}, +/* 0x21 */ {dxgkio_get_context_process_scheduling_priority, + LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY}, +/* 0x22 */ {dxgkio_get_context_scheduling_priority, + LX_DXGETCONTEXTSCHEDULINGPRIORITY}, /* 0x23 */ {}, /* 0x24 */ {}, /* 0x25 */ {dxgkio_lock2, LX_DXLOCK2}, @@ -4669,8 +4836,10 @@ static struct ioctl_desc ioctls[] =3D { /* 0x2c */ {dxgkio_reclaim_allocations, LX_DXRECLAIMALLOCATIONS2}, /* 0x2d */ {}, /* 0x2e */ {dxgkio_set_allocation_priority, LX_DXSETALLOCATIONPRIORITY}, -/* 0x2f */ {}, -/* 0x30 */ {}, +/* 0x2f */ {dxgkio_set_context_process_scheduling_priority, + LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY}, +/* 0x30 */ {dxgkio_set_context_scheduling_priority, + LX_DXSETCONTEXTSCHEDULINGPRIORITY}, /* 0x31 */ {dxgkio_signal_sync_object_cpu, LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU}, /* 0x32 */ {dxgkio_signal_sync_object_gpu, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index 46b9f6d303bf..a9bafab97c18 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -708,6 +708,26 @@ struct d3dkmt_submitcommandtohwqueue { #endif }; =20 +struct d3dkmt_setcontextschedulingpriority { + struct d3dkmthandle context; + int priority; +}; + +struct d3dkmt_setcontextinprocessschedulingpriority { + struct d3dkmthandle context; + int priority; +}; + +struct d3dkmt_getcontextschedulingpriority { + struct d3dkmthandle context; + int priority; +}; + +struct d3dkmt_getcontextinprocessschedulingpriority { + struct d3dkmthandle context; + int priority; +}; + struct d3dkmt_setallocationpriority { struct d3dkmthandle device; struct d3dkmthandle resource; @@ -1419,6 +1439,10 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) #define LX_DXFLUSHHEAPTRANSITIONS \ _IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions) +#define LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x21, struct d3dkmt_getcontextinprocessschedulingpriority) +#define LX_DXGETCONTEXTSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x22, struct d3dkmt_getcontextschedulingpriority) #define LX_DXLOCK2 \ _IOWR(0x47, 0x25, struct d3dkmt_lock2) #define LX_DXMARKDEVICEASERROR \ @@ -1431,6 +1455,10 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x2c, struct d3dkmt_reclaimallocations2) #define LX_DXSETALLOCATIONPRIORITY \ _IOWR(0x47, 0x2e, struct d3dkmt_setallocationpriority) +#define LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x2f, struct d3dkmt_setcontextinprocessschedulingpriority) +#define LX_DXSETCONTEXTSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x30, struct d3dkmt_setcontextschedulingpriority) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x31, struct d3dkmt_signalsynchronizationobjectfromcpu) #define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5F9BF3FB06B for ; Thu, 19 Mar 2026 20:25:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951949; cv=none; b=PiOSMvgODF8WsRAdMFOc1hbuqjmG2sXnsSyFFIKOiurRbUTNMx3YT3Es4zicBCy+U44Jp08I7ew+O+7kVN5yOPo/OIYuv5xjbXBG57xVhhAeXA1lbGzawNuRjiHHidUv9sKcWRMTC9naJ99Xmsusd5mP7MGWg0Mkjzw2U+eoS9w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951949; c=relaxed/simple; bh=PrVjDos1wa71PrV7Y/ZBU6TbhGZpn+nSvhkDy9ptgyI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iUgTDlvn5FbmYN1psfyyH/d3sXZwXwOcnCKjXFpkCKlhzCj0CoxVJot8B4BhdIlidmNkmvULGpAwx4piO+/jHoLRxXS/+Rj6yvjzDBFgtRsElwR0wjfHv9qYQedO3ckyB11E9/q2+4nvP3dFUv5QkatDjlxYNjDOilcrUSByfFc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=K0kT3v+7; arc=none smtp.client-ip=209.85.221.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="K0kT3v+7" Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-43b4d734678so1373082f8f.1 for ; Thu, 19 Mar 2026 13:25:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951943; x=1774556743; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=VRkcrNVWoDrrgx573fUCy9gOqPQFhMLeiPub9tIbpRM=; b=K0kT3v+7/AbKjrFzw65r9vHJ1GO/YJ+mPGurrUqgk/MN5iGHfHJTJ/+daXi50RIJ1H iOpYOclJ5+Bc1m4c1RaIHjZawWKz80aVGl8q2o7UNcubJa/UPegHs0xVG2rWCFFIhpPD iX5h4e5uMTzSMw0RQX2LT6MZgzz0tkeIqdre87vt9nfKvAsI/1LpvYRLfnuEqTxFHEU8 0IpSmpUaotchqBqJFlhXBJJUCdOW5sDijud3F1yruF+mfhUgEDKg8fkLQ9lT95bh9QQT 7nvGZQp3kZwihs4/Bv9G1y0cul0wiui72GFXPXPUGB5aQin8d+RfeSBeHh6oNHUqZczX ml+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951943; x=1774556743; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=VRkcrNVWoDrrgx573fUCy9gOqPQFhMLeiPub9tIbpRM=; b=o1cGPPeCDV8eT/cv03rrY1BktTn3Oywxwx7z9QrmQHBNE9RixJnWyGR3R2AmI+jwKO M4Mvlj9OEzm/aFOJ4voT+9tbMVi5r4YPwSHEGLlTrUcxJBpSeduJ8OZXmYWVNrf6MjVl CzMkO/z5GdLh01dax5GkFww03E5rl9rbmtPLIWVTJQHbfjq6FAxIuBLELTPqwZfKV1Wz P5+7mZzndwLpJjFGUE1O94nGUf7aRBFu+EorzzwAP9yWVAdJhutz/psVvAV5vbHO0VfR XS2tb04E1wIfWbhrQnCpAuu5VvuML0evkmA6lewa0tGpU78+xspwxYTouHhQJH/Gr8Bt 4zZA== X-Gm-Message-State: AOJu0Yw8U7p6If8t4BrBgZR4mXnnPS6LYwO5ewwUpX1u/Ze+qpd3xF9C lrBrUdprNzBWGgPmTcT+OEAyhIUPeq7q8ob1/ZU3+lzVYrvJLK0T1UJQ X-Gm-Gg: ATEYQzwwXTvAfWwu5CuZZb2fe9+Qo76fvP3aX90EMB/oBlJ2Uw1m+sYcmWrh3bxRE74 6aQqIiJ3OYPlgkrtvqCVlJjzxO48zzI3GqrRnXvmpKiPkr7BrnTCHIevxcu9CursdKMjkCScgzX zP9/NwMN+doHSpq+pYF4CKnGalFitOXnghEXDGPIPfCWalvyWWsa6qBlEqfsXWqksozVHJL/vyl GN9v3+EwMH/jbMq4lG3/TonK/923AFTb9iS1t1WGiz/6GZhzdibwXz/oMJCmpEFuTNTjB/Azpuf 4RIipf4iPDzglCmwzFwpzLB2i6ETdeMACpLVyMd46/OKd4pXww8QLF9BgViciFyu2Rvnx8d9gn7 0vb/z68wczh6rGfSn5ymeWPG9+9TSVC/24fG+HWJTnkwmvSabyPyQPT1zbNK4UzVwyh3yINpvdb 4/henrfXl3T2uDyFSQRwFIHQs4ZMNn8PeFycC4GHYx1bb9q1Vu X-Received: by 2002:a05:6000:2f84:b0:439:ac98:751f with SMTP id ffacd0b85a97d-43b642424d6mr1106631f8f.23.1773951943370; Thu, 19 Mar 2026 13:25:43 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.42 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:42 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 26/55] drivers: hv: dxgkrnl: Manage residency of allocations Date: Thu, 19 Mar 2026 20:24:40 +0000 Message-ID: <20260319202509.63802-27-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 *p= r, 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 *ad= apter, + 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; } =20 +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 =3D { }; + struct dxgkvmb_command_makeresident *command =3D NULL; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + cmd_size =3D (args->alloc_count - 1) * sizeof(struct d3dkmthandle) + + sizeof(struct dxgkvmb_command_makeresident); + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + ret =3D copy_from_user(command->allocations, args->allocation_list, + args->alloc_count * + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy alloc handles"); + ret =3D -EINVAL; + goto cleanup; + } + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_MAKERESIDENT, + process->host_handle); + command->alloc_count =3D args->alloc_count; + command->paging_queue =3D args->paging_queue; + command->flags =3D args->flags; + + ret =3D 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 =3D result.paging_fence_value; + args->num_bytes_to_trim =3D result.num_bytes_to_trim; + ret =3D 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 =3D { }; + struct dxgkvmb_command_evict *command =3D NULL; + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + cmd_size =3D (args->alloc_count - 1) * sizeof(struct d3dkmthandle) + + sizeof(struct dxgkvmb_command_evict); + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + ret =3D copy_from_user(command->allocations, args->allocations, + args->alloc_count * + sizeof(struct d3dkmthandle)); + if (ret) { + DXG_ERR("failed to copy alloc handles"); + ret =3D -EINVAL; + goto cleanup; + } + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_EVICT, process->host_handle); + command->alloc_count =3D args->alloc_count; + command->device =3D args->device; + command->flags =3D args->flags; + + ret =3D 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 =3D 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; }; =20 +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 *proces= s, void *__user inargs) return ret; } =20 +static int +dxgkio_make_resident(struct dxgprocess *process, void *__user inargs) +{ + int ret, ret2; + struct d3dddi_makeresident args; + struct d3dddi_makeresident *input =3D inargs; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.alloc_count > D3DKMT_MAKERESIDENT_ALLOC_MAX || + args.alloc_count =3D=3D 0) { + DXG_ERR("invalid number of allocations"); + ret =3D -EINVAL; + goto cleanup; + } + if (args.paging_queue.v =3D=3D 0) { + DXG_ERR("paging queue is missing"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + args.paging_queue); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D 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 =3D=3D STATUS_PENDING || ret =3D=3D 0)) { + DXG_ERR("Unexpected error %x", ret); + goto cleanup; + } + + ret2 =3D copy_to_user(&input->paging_fence_value, + &args.paging_fence_value, sizeof(u64)); + if (ret2) { + DXG_ERR("failed to copy paging fence"); + ret =3D -EINVAL; + goto cleanup; + } + + ret2 =3D 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 =3D -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 =3D inargs; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + if (args.alloc_count > D3DKMT_MAKERESIDENT_ALLOC_MAX || + args.alloc_count =3D=3D 0) { + DXG_ERR("invalid number of allocations"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_evict(process, adapter, &args); + if (ret < 0) + goto cleanup; + + ret =3D 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 =3D -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[] =3D { /* 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[] =3D { /* 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; }; =20 +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 =3D 0, _D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL =3D 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 \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 661D43FB7DD for ; Thu, 19 Mar 2026 20:25:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951951; cv=none; b=CqF8nOOCxktrXkjo/o4fZVoSnCyEIqS03CKK4fmIg2433YdIYdPIsjVR5fOTbGiSeIgneyMH1ZgIC7PSzJI8NDXDWpfVa2Mm04/b61Zu2tdbmU3KlHwrrXbHs2Z1G22TQTmYL1MkR1x3ZX2KKfFUqIYbfaT0HAfEIkSq8/gQqbg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951951; c=relaxed/simple; bh=L4ollWAJ/W7Q1vX0Fn+b8oAXLwAJ9050OT+TDiUSc9k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=spbFhp3XIXEvnkWfXFD81Xgny9NZqnwHuw97jFIQUm3u2P6Syik7+U4DdEuiOldsctHxBckw7LN9ZAu04C03mkVOJEw/Lc7k8dZD8jaCxbMYFy77NJ9Sadm0L6xvR620vpCTIguYTIykDkxB47IKMFrGCNyKwWFJ4HP2guis4Us= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=M6f8tUbR; arc=none smtp.client-ip=209.85.221.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="M6f8tUbR" Received: by mail-wr1-f50.google.com with SMTP id ffacd0b85a97d-43b3f91a7abso759808f8f.1 for ; Thu, 19 Mar 2026 13:25:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951945; x=1774556745; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GwngdvO9y1yS2wABD/u0qPlNd/XIEvwIA6MgEWtPNo4=; b=M6f8tUbRbuTjdaeX0ptWZ3wenXIAvCWcXlnwDiNmktB8yhC/j7xMcL168a6b8harsw KeTu+K6OktQstQcokcxv1nmKim0dQqmohfR96KUZTVc3HzbNwGEEEAcu04pLYo5FpwJO r9tDaIV/NYI+9wTKrZpLlZCJmt6zW/MdplG13m4gUrB3hPDasLEkbqJ1E3EcGMgrGRE4 J7s1llddoTwejCa5XvKVf56/1fqqgseRlEkLGx2BK3AW9ct/AV4Dlvm3ivm5zMrlpEqm nC0pDNTnA6o2b+zom20HTemxdaRoLZeBLESglMgrRJyyrxhbE/r8sStkMDUA+j3Di2my h0uA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951945; x=1774556745; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=GwngdvO9y1yS2wABD/u0qPlNd/XIEvwIA6MgEWtPNo4=; b=bNjmkHEP2hBYaF7STLV8Ua+MC1IgVlSO2B9ZpMyZ4ik6fUJme9yQawiMXnGPaXupEA FQxJR+hp6wrMmZGSKzusI+gw1EqiOtBxAqAl1BNy3yX31qpdV/hEHeBpo4jm7fDVGKV0 WoQ7QnWu6be8CLL2+ogZVMiHtllwBS44zdhh+U6Py0lqDRhNmKsgSd2BXzoM8abqxCfH rlxq942lZdKVnCAqdN437y10cfa1YEUxiwsznlw/i5elZK9YSYmUhdq21Yon0OPupFfr tMRgjhMdl3vQl0NrmLuv2/+2TR2AncwDPUs041ZJtr+JKFAE6CqhkQO+IXyzeZcoy/9p UzuQ== X-Gm-Message-State: AOJu0YwhUyxjOMPMmJGCtNn0aZMjJch9EzYSaHDDl3yO64/hdN+t1w2+ TRLGs9nyQyYjFpzHfooFUJVd48Krrjmk/UTBol4vcLoZLjiE85/CUuWs X-Gm-Gg: ATEYQzzoGH/xxNqd6UxgNlF4SFNPAzfTlM642YMMYKixGdIlnuTukkkhYuZzZ47ME2D 9wyvg4PWLCHV3AlcZIVp6AaSTBoJbBJzag0k6MhjzM25uL6pWk8ZuLEC3ARfg8bU0JOAcjaQ8db AifVcrF2JfB57Jq+D5dvY6eO0wIiy36CzPdOa6aTEVNMKy7kPMlhJeOCcucoe6S5I2GftG3YTGy YmE98bQvCah8/xiSl5ttD/CKIVcQxD3Ql/MDU7E2DHmbgYNLXldLCWG3JUqydXuXcbOpEfv86Dc tSgTUurGJCn8Wo9YuLFQz11oLzNsOJIqJIwBj+uPh989cBoc282hLMt9rRjyMb4hLtW+gmg1BD4 vOFJg7GAtfQDTuEjhuTtU8FtniHx2/C9nvMMDF5ICxQdqw+qbaCGEGk0JWCUPIu/Jdj3GS79rwR e/i8cqyPGm/MOGyjrAMRstxGbLaU2G+BSkIwffVMINZvAV9akQ X-Received: by 2002:a5d:5f87:0:b0:43b:4f86:e996 with SMTP id ffacd0b85a97d-43b6427ea9bmr1145983f8f.29.1773951944616; Thu, 19 Mar 2026 13:25:44 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.43 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:44 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 27/55] drivers: hv: dxgkrnl: Manage compute device virtual addresses Date: Thu, 19 Mar 2026 20:24:41 +0000 Message-ID: <20260319202509.63802-28-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 dx= gadapter *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 *adap= ter, + struct d3dkmt_freegpuvirtualaddress *args); +int dxgvmb_send_update_gpu_va(struct dxgprocess *pr, struct dxgadapter *ad= apter, + 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 *p= rocess, return ret; } =20 +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 =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_MAPGPUVIRTUALADDRESS, + process->host_handle); + command->args =3D *args; + command->device =3D device; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result, + sizeof(result)); + if (ret < 0) + goto cleanup; + args->virtual_address =3D result.virtual_address; + args->paging_fence_value =3D result.paging_fence_value; + ret =3D 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 =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_RESERVEGPUVIRTUALADDRESS, + process->host_handle); + command->args =3D *args; + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, &result, + sizeof(result)); + args->virtual_address =3D 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 =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_FREEGPUVIRTUALADDRESS, + process->host_handle); + command->args =3D *args; + + ret =3D 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 =3D {.hdr =3D NULL}; + + if (args->num_operations =3D=3D 0 || + (DXG_MAX_VM_BUS_PACKET_SIZE / + sizeof(struct d3dddi_updategpuvirtualaddress_operation)) < + args->num_operations) { + ret =3D -EINVAL; + DXG_ERR("Invalid number of operations: %d", + args->num_operations); + goto cleanup; + } + + op_size =3D args->num_operations * + sizeof(struct d3dddi_updategpuvirtualaddress_operation); + cmd_size =3D sizeof(struct dxgkvmb_command_updategpuvirtualaddress) + + op_size - sizeof(args->operations[0]); + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_UPDATEGPUVIRTUALADDRESS, + process->host_handle); + command->fence_value =3D args->fence_value; + command->device =3D args->device; + command->context =3D args->context; + command->fence_object =3D args->fence_object; + command->num_operations =3D args->num_operations; + command->flags =3D args->flags.value; + ret =3D copy_from_user(command->operations, args->operations, + op_size); + if (ret) { + DXG_ERR("failed to copy operations"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D 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; }; =20 +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 *pr= ocess, void *__user inargs) return ret; } =20 +static int +dxgkio_map_gpu_va(struct dxgprocess *process, void *__user inargs) +{ + int ret, ret2; + struct d3dddi_mapgpuvirtualaddress args; + struct d3dddi_mapgpuvirtualaddress *input =3D inargs; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + args.paging_queue); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D 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 =3D=3D STATUS_PENDING || ret =3D=3D 0)) { + DXG_ERR("Unexpected error %x", ret); + goto cleanup; + } + + ret2 =3D 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 =3D -EINVAL; + goto cleanup; + } + + ret2 =3D copy_to_user(&input->virtual_address, &args.virtual_address, + sizeof(args.virtual_address)); + if (ret2) { + DXG_ERR("failed to copy va to user"); + ret =3D -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 =3D inargs; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGPAGINGQUEUE, + args.adapter); + if (device =3D=3D NULL) { + DXG_ERR("invalid adapter or paging queue: 0x%x", + args.adapter.v); + ret =3D -EINVAL; + goto cleanup; + } + adapter =3D device->adapter; + kref_get(&adapter->adapter_kref); + kref_put(&device->device_kref, dxgdevice_release); + } else { + args.adapter =3D adapter->host_handle; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + kref_put(&adapter->adapter_kref, dxgadapter_release); + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_reserve_gpu_va(process, adapter, &args); + if (ret < 0) + goto cleanup; + + ret =3D copy_to_user(&input->virtual_address, &args.virtual_address, + sizeof(args.virtual_address)); + if (ret) { + DXG_ERR("failed to copy VA to user"); + ret =3D -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 =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + kref_put(&adapter->adapter_kref, dxgadapter_release); + adapter =3D NULL; + goto cleanup; + } + + args.adapter =3D adapter->host_handle; + ret =3D 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 =3D inargs; + struct dxgadapter *adapter =3D NULL; + struct dxgdevice *device =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EINVAL; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + + ret =3D dxgvmb_send_update_gpu_va(process, adapter, &args); + if (ret < 0) + goto cleanup; + + ret =3D 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 =3D -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[] =3D { /* 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[] =3D { /* 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[] =3D { 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; }; =20 +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 =3D 0, + _D3DDDI_UPDATEGPUVIRTUALADDRESS_UNMAP =3D 1, + _D3DDDI_UPDATEGPUVIRTUALADDRESS_COPY =3D 2, + _D3DDDI_UPDATEGPUVIRTUALADDRESS_MAP_PROTECT =3D 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 =3D 0, + _D3DDDIGPUVA_RESERVE_ZERO =3D 1, + _D3DDDIGPUVA_RESERVE_NO_COMMIT =3D 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 =3D 0, _D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL =3D 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 \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E920A3FBEA4 for ; Thu, 19 Mar 2026 20:25:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951952; cv=none; b=ekUO6c2N7VfQuodXGfPU4hHKQGyFAf8TafvCV32lB969lZWA/rPrmTHRJM7QDGNT9utvwL4sYOis6QXP+Tg28QdaGeOXuvfLs6lLktITC935mMwhfieLilFmNSNWOLn/X+6mxMM36tikXT+UlM1F5nC+PyisRv2vhnqN/BzjF9A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951952; c=relaxed/simple; bh=0mnqW+0YxMPWWQ5hYRM9j1JibATge5yEVOcZ4JbBf18=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Zd+PvINAUeXNMvoo187XactTB75SMc6aXtMEApRaAF5Lrki4gcE0RfPYxcx1E49sTf0vRq9p3GjXWAMw9opJVimHwvMpNGBHDTzNt06TH9R1WNvvbQjgkxsvbiYSs/hv4px/1WO9xGSpUSL6m4KJ//NJ4xky/QdGzRNp1dB2nZ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Bh8HIKvn; arc=none smtp.client-ip=209.85.221.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Bh8HIKvn" Received: by mail-wr1-f42.google.com with SMTP id ffacd0b85a97d-43b40003d13so878630f8f.2 for ; Thu, 19 Mar 2026 13:25:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951946; x=1774556746; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wzkntaQrinqqPXBhUAC5ve0qVCkj/uMJtIw3Tw3VCWE=; b=Bh8HIKvn+bkd9eZgWfGIy3JOhwXPb5sSZQ9lCaZ6wHRYb6V/VxswkhRZqFcofbYVdq KY3rLjSXOcxnu3RquP/PQNS5qvN/i3+sp7BUVGlKjjLCOulyE443U20R2tJQPtWuzB2X bx5n8O0ZaD2CPCmAgb2kpNPT3lTAR7Uatez2xd3gQGWp02Vi58rOofL6dp1Zt11ZrTgs 68W6qefD2clUynPXPowSUfYitKk82ulUXaowuNnjhNtDB2JfwCLADs74xv68vxZaB3Vr dFLu2ABCkhr8NkucWRrFNpIkp8xSo8Okg9E+tJgKGN9b+nvaRGNZkJEDuEgRKLofnBm6 1Nug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951946; x=1774556746; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=wzkntaQrinqqPXBhUAC5ve0qVCkj/uMJtIw3Tw3VCWE=; b=Luh8Xgg9dSSpqlgjyzxWo7N71bCBKJQAzSf9/xaKWWV0xzG7zHjpwGuNbSP8+Yn1TF 0aOe6QGPvtkdCqepDQr4vbitDb2VKPHwsqCqbbQY4jrwGIACGebJ7eFWufOsubXa667x v+FNs+T9qLchtxy83S8niahHkt38DcGn3a16RUyYK775o3j367GiyNo+EAuCuVu/1UVS 05nibkjdKbyxx6KZhrhoTrPykisijA3IYgtNySlB3s/btstBMqFyA2p1zmaCYkcIjLDY tSFj9gtC6b6ahnTp4Y8zv6kTTRV5ptERUYsEBQq4a9ZzwIg048665eUt/bEmxVx2blTM yUcQ== X-Gm-Message-State: AOJu0Yw5Yprp0hLfwIVUZo1dt876PB6M2OKioxVdaBA4nC7CaGHPHgkv zXjDp3rBdn28nfUD4URlKMvbqeE5S7HHp/y9kag3dsGX2iGAQnmIdL+f X-Gm-Gg: ATEYQzyhO7y0T32PT6Eup/c1mLv1GUpRLCz/iAbdHU2NQD2It1WTtVxtjTxQN3vNAL6 a6OTDDd+QeJ9gGkqj/KTEZP1zzViF9wfp323TaG8kjZ+AKvmAyupJDRrtnZ5Tm9iDK3/U6rWvOJ 656Po0Dhu+DJQRgJE5L2j/DigwM4CFBZm2YIfMjHnjGQhe/nRcH8n1cNTlN5NmLzR2on09DR89f qZ5kKu4NVp5ZfOq37nXfdW30pavj2ay2rzVHMuqDR2c0luaZu2ciTyXeMP/451Yu5EZiDYtDAiZ vXeCuxaDofN6hEWdmoMVmFnfggLcsy2WErKHrQiwCkFbEAMXQr01H9wPOYedLuYBcYTovjasU07 WfR6+ovzxs/bDDT5cj26Jjv1Cy4OlBTiMPTFUVcI4hA3j8iYlfLxW2njhzLcTUWedxDDYomFi8N DvnAfWJq5XnI/w9ZY7wLftV2v1L4DQlTBxm++c1OsuNBoRReLR X-Received: by 2002:a5d:64c6:0:b0:439:df03:f300 with SMTP id ffacd0b85a97d-43b6428178emr1154879f8f.40.1773951945847; Thu, 19 Mar 2026 13:25:45 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.44 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:45 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 28/55] drivers: hv: dxgkrnl: Add support to map guest pages by host Date: Thu, 19 Mar 2026 20:24:42 +0000 Message-ID: <20260319202509.63802-29-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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). =20 obj-$(CONFIG_DXGKRNL) +=3D dxgkrnl.o -dxgkrnl-y :=3D dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o = dxgprocess.o +dxgkrnl-y :=3D dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o d= xgprocess.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; }; =20 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 *e= vent) =20 void signal_host_cpu_event(struct dxghostevent *eventhdr) { - struct dxghosteventcpu *event =3D (struct dxghosteventcpu *)eventhdr; + struct dxghosteventcpu *event =3D (struct dxghosteventcpu *)eventhdr; =20 if (event->remove_from_list || event->destroy_after_signal) { @@ -426,7 +426,11 @@ const struct file_operations dxgk_fops =3D { #define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \ sizeof(u32)) =20 -/* 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)) =20 @@ -441,6 +445,23 @@ struct dxgk_vmbus_guestcaps { }; }; =20 +/* + * 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 =3D {}; struct dxgk_vmbus_guestcaps guest_caps =3D {.wsl2 =3D 1}; struct dxgglobal *dxgglobal =3D dxggbl(); + struct dxgk_vmbus_hostcaps host_caps =3D {}; =20 mutex_lock(&dxgglobal->device_mutex); =20 @@ -503,6 +525,13 @@ static int dxg_pci_probe_device(struct pci_dev *dev, if (ret) goto cleanup; =20 + ret =3D pci_read_config_dword(dev, DXGK_VMBUS_HOSTCAPS_OFFSET, + &host_caps.host_caps); + if (ret =3D=3D 0) { + if (host_caps.map_guest_memory) + dxgglobal->map_guest_pages_enabled =3D true; + } + if (dxgglobal->vmbus_ver > DXGK_VMBUS_INTERFACE_VERSION) dxgglobal->vmbus_ver =3D 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 =3D NULL; int ret =3D 0; struct dxgkvmb_command_setexistingsysmemstore *set_store_command; + struct dxgkvmb_command_setexistingsysmempages *set_pages_command; u64 alloc_size =3D host_alloc->allocation_size; u32 npages =3D alloc_size >> PAGE_SHIFT; struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; - - ret =3D init_message(&msg, device->adapter, device->process, - sizeof(*set_store_command)); - if (ret) - goto cleanup; - set_store_command =3D (void *)msg.msg; + const u32 max_pfns_in_message =3D + (DXG_MAX_VM_BUS_PACKET_SIZE - sizeof(*set_pages_command) - + PAGE_SIZE) / sizeof(__u64); + u32 alloc_offset_in_pages =3D 0; + struct page **page_in; + u64 *pfn; + u32 pages_to_send; + u32 i; + struct dxgglobal *dxgglobal =3D dxggbl(); =20 /* * 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); =20 dxgalloc->cpu_address =3D (void *)sysmem; + dxgalloc->pages =3D vzalloc(npages * sizeof(void *)); if (dxgalloc->pages =3D=3D NULL) { DXG_ERR("failed to allocate pages"); @@ -1419,39 +1424,87 @@ int create_existing_sysmem(struct dxgdevice *device, ret =3D -ENOMEM; goto cleanup; } - kmem =3D vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL); - if (kmem =3D=3D NULL) { - DXG_ERR("vmap failed"); - ret =3D -ENOMEM; - goto cleanup; - } - ret1 =3D vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem, - alloc_size, &dxgalloc->gpadl); - if (ret1) { - DXG_ERR("establish_gpadl failed: %d", ret1); - ret =3D -ENOMEM; - goto cleanup; - } + if (!dxgglobal->map_guest_pages_enabled) { + ret =3D init_message(&msg, device->adapter, device->process, + sizeof(*set_store_command)); + if (ret) + goto cleanup; + set_store_command =3D (void *)msg.msg; + + kmem =3D vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL); + if (kmem =3D=3D NULL) { + DXG_ERR("vmap failed"); + ret =3D -ENOMEM; + goto cleanup; + } + ret1 =3D vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem, + alloc_size, &dxgalloc->gpadl); + if (ret1) { + DXG_ERR("establish_gpadl failed: %d", ret1); + ret =3D -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 =20 - command_vgpu_to_host_init2(&set_store_command->hdr, - DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE, - device->process->host_handle); - set_store_command->device =3D device->handle; - set_store_command->device =3D device->handle; - set_store_command->allocation =3D host_alloc->allocation; + command_vgpu_to_host_init2(&set_store_command->hdr, + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE, + device->process->host_handle); + set_store_command->device =3D device->handle; + set_store_command->allocation =3D host_alloc->allocation; #ifdef _MAIN_KERNEL_ - set_store_command->gpadl =3D dxgalloc->gpadl.gpadl_handle; + set_store_command->gpadl =3D dxgalloc->gpadl.gpadl_handle; #else - set_store_command->gpadl =3D dxgalloc->gpadl; + set_store_command->gpadl =3D dxgalloc->gpadl; #endif - ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); - if (ret < 0) - DXG_ERR("failed to set existing store: %x", ret); + ret =3D 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 =3D init_message(&msg, device->adapter, device->process, + sizeof(*set_pages_command) + + max_pfns_in_message * sizeof(u64)); + if (ret) + goto cleanup; + set_pages_command =3D (void *)msg.msg; + command_vgpu_to_host_init2(&set_pages_command->hdr, + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES, + device->process->host_handle); + set_pages_command->device =3D device->handle; + set_pages_command->allocation =3D host_alloc->allocation; + + page_in =3D dxgalloc->pages; + while (alloc_offset_in_pages < npages) { + pfn =3D (u64 *)((char *)msg.msg + + sizeof(*set_pages_command)); + pages_to_send =3D min(npages - alloc_offset_in_pages, + max_pfns_in_message); + set_pages_command->num_pages =3D pages_to_send; + set_pages_command->alloc_offset_in_pages =3D + alloc_offset_in_pages; + + for (i =3D 0; i < pages_to_send; i++) + *pfn++ =3D page_to_pfn(*page_in++); + + ret =3D 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 +=3D pages_to_send; + } + } =20 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; }; =20 +/* 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] =3D 0; return dest; } + From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AEB233FBEBC for ; Thu, 19 Mar 2026 20:25:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951951; cv=none; b=chgs+H137ixba75LJFV9XIP/38uj/JgLT1cpG/6fmIGXwSkKdkyquyu7G4IZzBFX0l51zlZO+dJvJgwaqo5iHQueGCfSzdK2v7YiH7H1J2UzE83eplTnhalB7Y3Jr0lyv90C5jnv/CBojCQAwR9WbnMVXugHPHd2d1sPgijZtTA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951951; c=relaxed/simple; bh=8pci5keNCSZIRItQgwBd9jTB/soEr+3j3n73ramG7Do=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YeuDw17BJ2BRbzlAlVavi7p/iq17Pb8snMv7yHw1FeYbqftwEDy1u/ajXfuMrxJ89v1BkerjvAA/NJZ8rSeZUKSc6EsarGt74xUp5dTNO38R/czoVoRLJrLFJinr9iQe7pFRsuUhchFyjAvSqLFibhpvSK5m3ziR+nXy6sR2/m4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=f8D3H2q/; arc=none smtp.client-ip=209.85.221.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="f8D3H2q/" Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-439b6d9c981so858106f8f.1 for ; Thu, 19 Mar 2026 13:25:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951947; x=1774556747; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=t30r0nJLZ+XoljLbUI5nWlW+9TZBNz/klLk5d0iuzjM=; b=f8D3H2q/DYz4fgI+MJgFdwQXlBRDylqxSM6zjV227Xbpj8CNRpWMredgnrrhMwKBEQ +R/Dmk/ZPhW6cXJQsu+LeJgy1bJu/eY2mOCz422dEG4OZITrByBlgFl5YjausggbiNjK rUVKXbTvWk1ckqH4H4Tzo2o8QXWADqKRRuMUXVZ8I5T4iSLCVzqwQ+P4u/jMqF6x+Ttc Wp6uHad1zUwAOmUcQtnHA3N3Us4f5xRrr1SrlFFQdDenx+UhmOazK34k9NuC9fLN+ksi GKQxHDZs200C3L6xg2w3ba4UFnaiTUIHsPzfz3FLD7J24PhTLE09guXWS1DpNmynPk1C bR2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951947; x=1774556747; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=t30r0nJLZ+XoljLbUI5nWlW+9TZBNz/klLk5d0iuzjM=; b=CIv/1a4zIB+GHcoHICelyx4j2BFQ+YOiqZ+K6mNMzh0TnRJOOU5yDd81RWmPltTYdV sg8W98jr1XRmHUf55ybqqWkGqZYSY80IN9OsCALhkSU2BbiwzItIJ+BVJFxR4AdJOqDR h5u3V/f2XBBAsoYcDGxHf/0O7n7UIvi/eKv8o9rvKte75GhOWYSgtuqs8wZlN4RtWrd6 lR5LZQIxUu//mR+gXFIC8o5JXJAaD8XGuDIqe6ixV0laG23SjKJv3BuFqBwrIDaaO3eM KCdieW6sxHUhwMyTO0gf8pSjTs6cvQN2cY43WiVvsIRNdgQGaSJhtHIfIC5spQDXL5UQ e8ew== X-Gm-Message-State: AOJu0YweZXNL+kd/UPfk4swpSUVcjk4y13JuBQXNtMYgia4HekjvhjE9 u5m2KO0RrddvzUrbOQ4rMOiEfprVzL4v03st+UFxgZ0HBptWn4zTacYL X-Gm-Gg: ATEYQzw1YTSKFFkUwG+7XxoJdirq8OkvzUgOWfokcqv/Xk2bhV3DRUr7EwaGV2nHEzG seVQDdMVADLqaVSGMO6MScHa2abUH7URB7ZS3GpzOiu6OJOqsH3+pey5NNyD3ySvFOecWocEUGv lVkCwebx9Qn2mH+zp6/8qBg2vglHFQ/cEp8mKjdq3eiG/a79hVXz4QND0fc2ga6zOaAUXVEDsMg YMG4H/YJpvrgOQ4JNC+Ebgv41ebhgC0OFKhEI4LAHtcPMkYw/2LsIsbzQhVeCswiLSfODFJt+IQ 2VKA4dcSj8geUkZHFH5a2whu4zZFn28XLJEs2TqD0RMlWTQK5M7T47IGDxxTkQmQksQIyFEyJeJ ftGOGpPBmDBWwO/bsZkX6PH0ES7DldYa3ID/F+wonK7C5GGNTLaP0gK9Nwv52/A5qIyAjPwNmWc Iln4z9Rue9ZV42eAMU582a8jQyeJZ9jNQ2YXU8q24zdIfGhKGW X-Received: by 2002:a05:6000:4021:b0:43b:566e:fad2 with SMTP id ffacd0b85a97d-43b64242eb2mr1508120f8f.9.1773951946802; Thu, 19 Mar 2026 13:25:46 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.45 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:46 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 29/55] drivers: hv: dxgkrnl: Removed struct vmbus_gpadl, which was defined in the main linux branch Date: Thu, 19 Mar 2026 20:24:43 +0000 Message-ID: <20260319202509.63802-30-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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/dxgadapte= r.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 =3D 0; } -else +#else if (alloc->gpadl) { DXG_TRACE("Teardown gpadl %d", alloc->gpadl); vmbus_teardown_gpadl(dxgglobal_get_vmbus(), alloc->gpadl); From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f45.google.com (mail-wm1-f45.google.com [209.85.128.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EE2A63FCB05 for ; Thu, 19 Mar 2026 20:25:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951953; cv=none; b=jASoyuSM5v3C9aQklwKW9uqjtvmptRL+Le+5voh82sEvUoQdeK1xbNs955p5zISmZvE7xK7ydVVCNj0zsTdLodKy9N9ebl2IGkeF6vPciajbvKPgtPOvZafRedogqTqMwQMsPuOhv7YpMtqxVUOs49aNgUHpPYKdww4DbrCFeqE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951953; c=relaxed/simple; bh=oKy7K50U4xod7H9n2WA1hO9ZTdC4HWwRfYzOW8vTIGw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FtCKp++fRdEqXKEJkic89iS/VTnkf/lbpipuU7chk2C1eYOCq5Va03TTb4MW7d8Sx/v558nba4IGgbcFN5hoF5Bbl3GkDtHKKBCvlLGmpEeobOcqvBPlsej1nyjGNwLUlUNOB7Rh7eCaXQ78NZkqx971hBQnDdzxlj5zWR726Tw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=e3aOeCss; arc=none smtp.client-ip=209.85.128.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="e3aOeCss" Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-486fb14227cso12074065e9.3 for ; Thu, 19 Mar 2026 13:25:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951948; x=1774556748; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ckjfDHMjepp0Dv0WHHzgU1DF+dSRdE5LwZWVFCBJz5A=; b=e3aOeCssjX2RslYT1X0q3iwAMw2Un/xTG6FAEragbdFJfsTE/1VLHz6woCCMKHw1bn ytDCI3AUpgAyp+ZZ7/t6o4336pfP8aBjtjxM4ZwHE9GDIv7qAfRUfq7NwzCe2+tHGerD cLEmIDYnE0TjN+zz4Lu8y9a5VgZHCoSH1khT+EmDWhIRU2P2QRRHg2mwvK7t+DHMl4qk 8XvrxdUfDDkq2VRABmkRACXbbeQmkH4aZnjWMYdYu6JJwGaqzR+6YNhJsiTUHJPNxIKz PoH012wIwcJQxN0ZBumEO7BhmTdXO0Xn6B5N16aZ/XUp9OJt2fPIEUMxd0ES8mhjSzjH lF1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951948; x=1774556748; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ckjfDHMjepp0Dv0WHHzgU1DF+dSRdE5LwZWVFCBJz5A=; b=JT5J9dy93PEoKUuQlBvpsxJswLqDIRTTPlusWeiR/zgUZtloGOEv7qmcsRUF8wLfdM yRCXt6KDY81o0ISBr6Fp1rCl4VtAxKDiZ8MYUeUN6B7sWFJ+Yinb5mQsClrAnRHQyryD gL1RtSL5SQtoojBaVIIHu86O9nP2bNan5r2jAvRmTpJKOdGhWlZ3cQ3yv8TkxbUGv1Yy FGexZ6ryodR8CdSzUiWUwOajqw2M7jGxkmoxDT8+P6SmYT2+pIDLIZGHRWqyhmxwBBBK Nob67kjXUnsXlNa/Vbgx3Jc+STywLZ+9GkmpezF4XFe6+jXLBqfHWYkpONC9LmfyBCXd UzTg== X-Gm-Message-State: AOJu0YyOoNGpitqUrPx9McA+I/q+fTuMg34iyvYuu8GIMrSaWKvODlYo 9XEAEyz+uPYR185ASaASHMJfxrrQx0nWZYGeZxPPFEJPSGV5i4aM4p5j X-Gm-Gg: ATEYQzwIxFxaqvhUt17SZzHn/U9zzst6FcMAEFkID67nld7EaFzoBgXJNkM9yBBS7uV SQ/dpQoKazCxMvhQGC/hooHYRL89VQq6kDyCtEKGZtcIp/9i8xV7sDOWNaInYEO5u6pEgGgcaV4 sbnNcTX3Kyikv7nX4rOcPTFayhpdefX/DjwcTFw0sl+VG6NL0miXoaC6m/mWaZeUHmQOGA/D3oC L9+zs35WoHyqbp7mo2mZD5jA2UfJbQMo8iFGEZheND3oWKKYvmni6SQzhrsB3Pg/4Sz84aCN9Oi fRUwrEb67wl0GbYuhZ0Y+0nPa789pw6b574vup0zZXJjuPQqFrK8gOwmhvVmIZH0Es5XjVNWS9j n1M06QA3NnV5zwnaKBGGMl76HOvp7X2lxSbt0Nl3CqnT70ms1OFJhaGhC9Ko4xdktts51RMyy95 sDL5TExrA9vxHPBK4XO6g9l1XlAQ5wesyOyjSF/i3ehxgB8gNoIjj/omCCMq0= X-Received: by 2002:a05:600c:8508:b0:485:3b00:f92e with SMTP id 5b1f17b1804b1-486fedab7dbmr7342275e9.2.1773951947822; Thu, 19 Mar 2026 13:25:47 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.46 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:47 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 30/55] drivers: hv: dxgkrnl: Remove dxgk_init_ioctls Date: Thu, 19 Mar 2026 20:24:44 +0000 Message-ID: <20260319202509.63802-31-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov The array of ioctls is initialized statically to remove the unnecessary function. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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) } =20 /* - * 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; }; =20 #ifdef DEBUG @@ -91,7 +90,7 @@ static const struct file_operations dxg_resource_fops =3D= { }; =20 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, voi= d *__user inargs) } =20 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, voi= d *__user inargs) } =20 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, } =20 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 =3D inargs; @@ -5166,7 +5165,7 @@ static struct ioctl_desc ioctls[] =3D { /* 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[] =3D { 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}, From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D3EA13FCB1C for ; Thu, 19 Mar 2026 20:25:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951955; cv=none; b=AIPz8Rl22OxBQ8+F8BgiZ0xE758yMmefJkGRXBGBsRK6uJBl2aWobfBQrk6ghDjtx2hzYSBfSW76/X/j8iQIVYMSUHympdjJ7FGMEC9/7OTI6lBJUdLyJ1DjTlHVyO6BPaJXYLCdIIvt9gWlPwi/A9B2cRUjJAJz7YluTAh0UZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951955; c=relaxed/simple; bh=lbJJqathQ0RsrVpKR+Bj4fX/ytc5wlKUMv0nb6CZSto=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HznOQQ0lmhQjE9UKvjwGiJ1zGct6gH2S+lYhi7mjFnnBHsaX3DKyP6HpBX19K2HPMYD8pV6GSWx7d+H3A7Dr1+SAwPRp/A5t66mtB+1lbToKnnhgs/xBBRPViE41JRRr8SYbiYPFPEsMtXNpjtHG6QVzARbxy8Q3C7dL/8pAVnQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=gQCLFGJh; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gQCLFGJh" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-439cd6b0aedso839077f8f.1 for ; Thu, 19 Mar 2026 13:25:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951949; x=1774556749; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yfPgBA+Pl94DE98AaTxzZlc8zjDbPiM5ZxN+Lw61xBc=; b=gQCLFGJhUnFinELTygYYEzWUR+/WXM5Kz28y76QDI0MCPbKQd8fJCuLDKum6b7KvQf bL93M/B2C519lWOr5ehriWuYbPGwRwUObN80JE0WM4s9VtPYIpW23VUNVESmIShBwJAd N93bpGYT8iehtNGN/dJkMi/5W0q0SQk4TqyPWKlBkJF5mwfMYLv+lHB/xMWm6LCySIg9 3m7iwtw7NMdYzDZJpmfOFMRTleuJiOB3lpnk/p86x820hFTIk6DLY44gXJ4yP6QL4g08 98jO26vtonKsQcyyskIuNtZznzTI+MNkznhWl8n9tpF6JmDnuqKAihqFxhQN6HPiqV+h bWNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951949; x=1774556749; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=yfPgBA+Pl94DE98AaTxzZlc8zjDbPiM5ZxN+Lw61xBc=; b=h/NX7HhQPaDh9Foc7GeA/nz7IDm04oa0NQjlnH4WYEVFVaATmK2EohsXpZ5VRpkIVl XjJFNUpIxyNZbB+mcyzuubjSA45fBbfjFvTVTQhFC5+MtSlFtIHcffM//NbQMkB/ovN9 4wbmSjeebTNz+EJXcPQGfcnqw6hDkbPPFn6XpoDTgYSyjGVCe58Ki6oUm6WILZNL+/u2 flS3rjMR3050nSepbJpBrhTibusBSc84XWGmAgRoV6h+FWZKt3v8CIjZ6T/cn1PWPJeW eh6u7v25ydj6PPJ2b3gvCZ3ZZnfxM2lfiWhnQoZxJ2p4cEqrLS4R3nO1i0rWt3g6PzlY VH3A== X-Gm-Message-State: AOJu0YzT8dD3qLW9CpAOw0CpPT561nAOF9BNbEV7tjgtDpXEyACxfcMM s2DS5JC0JuKnq5PwOmrobCmJJhatz091X3ReYsAWMEsH0CaXoh0lT9XC X-Gm-Gg: ATEYQzyy0S0jPgqRtzNx7BUf+I5VQKDdZj3NCc/ruowv4AYM1nvZrs7y7uVBv0Sm6zA yEK8thZLMDJZysveaocBGcMH2pCRVgZTrhpvUOv8leY89Z2vFOPtU40p797VS0PTmcRsTKg0E9U NbCYn8GFOxUiMROBucOHLCcPSU+phfnImYF5+lmvF5JAwDCSAPPUDbuLHgz+oC4OZ8ncvHGP8Cz XWgBy6jItHsGG8Ykdpg76l9Ubo3iVMCwmod05JBeGQUEiIeMdU8BgGGiHByv/mlcaRtOhAi3Erk coaEEwP1SdH1loZIPLOddAmDIdv7jFL0qGatHjnRnUvIld0oCYLE6t6nyISQIn9ZiPPU80zNVaN vxNJb7Jiy8sfULMSwNmD+HJPFcZv22QDINVAsMsH28xbhIt9iXvXb+qRAjyBJNAHIRvrg6IjWbK rzJddwOuuAkGDGj5mrl2pbIpEe80Oyfn6SkaWtzp/V0FN4wmQV X-Received: by 2002:a05:6000:420c:b0:43b:460a:b13 with SMTP id ffacd0b85a97d-43b64281506mr1176416f8f.44.1773951948875; Thu, 19 Mar 2026 13:25:48 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.47 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:48 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 31/55] drivers: hv: dxgkrnl: Creation of dxgsyncfile objects Date: Thu, 19 Mar 2026 20:24:45 +0000 Message-ID: <20260319202509.63802-32-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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). =20 obj-$(CONFIG_DXGKRNL) +=3D dxgkrnl.o -dxgkrnl-y :=3D dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o d= xgprocess.o +dxgkrnl-y :=3D dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o d= xgprocess.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 =3D 1, + dxghostevent_dma_fence =3D 2, }; =20 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 #include #include "dxgkrnl.h" +#include "dxgsyncfile.h" =20 #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); } =20 +static void signal_dma_fence(struct dxghostevent *eventhdr) +{ + struct dxgsyncpoint *event =3D (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 =3D (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 =3D=3D dxghostevent_cpu_event) signal_host_cpu_event(event); + else if (event->event_type =3D=3D 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/dxgsyncf= ile.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 + * + * Dxgkrnl Graphics Driver + * Ioctl implementation + * + */ + +#include +#include +#include +#include +#include + +#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 !=3D &dxgdmafence_ops) + return NULL; + return container_of(fence, struct dxgsyncpoint, base); +} + +int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inarg= s) +{ + struct d3dkmt_createsyncfile args; + struct dxgsyncpoint *pt =3D NULL; + int ret =3D 0; + int fd =3D get_unused_fd_flags(O_CLOEXEC); + struct sync_file *sync_file =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dkmt_waitforsynchronizationobjectfromcpu waitargs =3D {}; + + if (fd < 0) { + DXG_ERR("get_unused_fd_flags failed: %d", fd); + ret =3D fd; + goto cleanup; + } + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EFAULT; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + DXG_ERR("dxgprocess_device_by_handle failed"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + DXG_ERR("dxgdevice_acquire_lock_shared failed"); + device =3D NULL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + DXG_ERR("dxgadapter_acquire_lock_shared failed"); + adapter =3D NULL; + goto cleanup; + } + + pt =3D kzalloc(sizeof(*pt), GFP_KERNEL); + if (!pt) { + ret =3D -ENOMEM; + goto cleanup; + } + spin_lock_init(&pt->lock); + pt->fence_value =3D args.fence_value; + pt->context =3D dma_fence_context_alloc(1); + pt->hdr.event_id =3D dxgglobal_new_host_event_id(); + pt->hdr.event_type =3D 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 =3D sync_file_create(&pt->base); + if (sync_file =3D=3D NULL) { + DXG_ERR("sync_file_create failed"); + ret =3D -ENOMEM; + goto cleanup; + } + dma_fence_put(&pt->base); + + waitargs.device =3D args.device; + waitargs.object_count =3D 1; + waitargs.objects =3D &args.monitored_fence; + waitargs.fence_values =3D &args.fence_value; + ret =3D 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 =3D (u64)fd; + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy output args"); + ret =3D -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 =3D NULL; + } + if (pt) + dma_fence_put(&pt->base); + if (fd >=3D 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 =3D 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 =3D to_syncpoint(fence); + if (syncpoint =3D=3D 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 =3D to_syncpoint(fence); + snprintf(str, size, "%lld", syncpoint->fence_value); +} + +static const struct dma_fence_ops dxgdmafence_ops =3D { + .get_driver_name =3D dxgdmafence_get_driver_name, + .get_timeline_name =3D dxgdmafence_get_timeline_name, + .enable_signaling =3D dxgdmafence_enable_signaling, + .signaled =3D dxgdmafence_signaled, + .release =3D dxgdmafence_release, + .fence_value_str =3D dxgdmafence_value_str, + .timeline_value_str =3D dxgdmafence_timeline_value_str, +}; diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.h b/drivers/hv/dxgkrnl/dxgsyncf= ile.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 + * + * Dxgkrnl Graphics Driver + * Headers for sync file objects + * + */ + +#ifndef _DXGSYNCFILE_H +#define _DXGSYNCFILE_H + +#include + +int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inarg= s); + +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 dxgproces= s *process, struct d3dkmt_waitforsynchronizationobjectfromcpu *args, + bool user_address, u64 cpu_event) { int ret =3D -EINVAL; @@ -2844,19 +2845,25 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgproc= ess *process, command->guest_event_pointer =3D (u64) cpu_event; current_pos =3D (u8 *) &command[1]; =20 - ret =3D copy_from_user(current_pos, args->objects, object_size); - if (ret) { - DXG_ERR("failed to copy objects"); - ret =3D -EINVAL; - goto cleanup; - } - current_pos +=3D object_size; - ret =3D copy_from_user(current_pos, args->fence_values, - fence_size); - if (ret) { - DXG_ERR("failed to copy fences"); - ret =3D -EINVAL; - goto cleanup; + if (user_address) { + ret =3D copy_from_user(current_pos, args->objects, object_size); + if (ret) { + DXG_ERR("failed to copy objects"); + ret =3D -EINVAL; + goto cleanup; + } + current_pos +=3D object_size; + ret =3D copy_from_user(current_pos, args->fence_values, + fence_size); + if (ret) { + DXG_ERR("failed to copy fences"); + ret =3D -EINVAL; + goto cleanup; + } + } else { + memcpy(current_pos, args->objects, object_size); + current_pos +=3D object_size; + memcpy(current_pos, args->fence_values, fence_size); } =20 ret =3D 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 @@ =20 #include "dxgkrnl.h" #include "dxgvmbus.h" +#include "dxgsyncfile.h" =20 #undef pr_fmt #define pr_fmt(fmt) "dxgk: " fmt @@ -3488,7 +3489,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *proces= s, void *__user inargs) } =20 ret =3D dxgvmb_send_wait_sync_object_cpu(process, adapter, - &args, event_id); + &args, true, event_id); if (ret < 0) goto cleanup; =20 @@ -5224,7 +5225,7 @@ static struct ioctl_desc ioctls[] =3D { /* 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}, }; =20 /* 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; }; =20 +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) =20 #endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 24D8E3F8E12 for ; Thu, 19 Mar 2026 20:25:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951955; cv=none; b=CqDxZtVB6Ruy2Ku4SJmljW1qUUwKfQbHUnFwtvj04KhRXexzRWj6OK3hXgy9pHiJFPnZIUwnjMMmz+2U/XZldD+2u6kxEd+W9j9AT2kqyGOFmNANg4m+z6bKe/lx9AxxEoYGFzBvSGFgmBCc9SnMg6K6Yd+YAggDTcPG3Tepm3E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951955; c=relaxed/simple; bh=YihQqAQ6+ZY8Dpxrl7tuuvKiO3QB5rOIAUJNhWwtaTU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LEiERDxqvXcQ/HE//e3aS59X6WlAyMxB0i+5TqxKVQI05ADNRuC7OWhHHcK6qZ7svgA7bayNQ8Sl3hObquyTJGh5B+Ln1ms38vatULY7TNBQhqH5Kyec8PRqAqbWoStCsq/I6diCqVMkPSif0eDX6MsmTjZEFP/MXHnIQgzRTZQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=REBlThlY; arc=none smtp.client-ip=209.85.128.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="REBlThlY" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-4852e9ca034so12261445e9.2 for ; Thu, 19 Mar 2026 13:25:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951950; x=1774556750; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=T5vGN3ll6taZ+ENdbw5uI+egqygk+hNP+j3J7qDiLXs=; b=REBlThlYoXa33aaVy8DZpdN2tHCNFp7AN4eQHoeygTqUs4vJWGCiRNhwduciEMgjTM 12oBkh8wuoiD/o1luN57IFFceg4KgLTuLjSNv9h25Tjy/ay+ueTxv6AgdCmlUThvtxKh E3ulRvBsn+J5hX55h/LOXXem8qtCngQ0Dg/FEjosfEOYhG29FtfDXGDNmqycS96uRFko /Sj+ARVWtA7HSdvWrgIxialerqfmc0tuDJ8xleh0RLj7YAVz8B0uMFaVCTDxb1OjWDX8 memOTi19L6nUkJoIerKfhhDP73rRGys4XG0KJFlm8DDNCzHmwygOg8Odb6LmmsUr4+c9 mb4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951950; x=1774556750; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=T5vGN3ll6taZ+ENdbw5uI+egqygk+hNP+j3J7qDiLXs=; b=PmoAJN702GVGPGWnZI2QBorEsZY9r0BYLjtpZFTxo9UISY3u0pW5sX2dNUZHQqvtbT lMKrfsRGcR1NoH2ZuJHlRVSAP7wOnaHCLsxJNl+vVB/M1zo31jk1baebUnkA82XafDvB W05UaP+ruVvlYHRnsh3SYtLNJhT2BVE++z/3uqE2Wxpj4R3r/XygWprFVxw3NrWENo/x 4aEntYUbNcbfpB7CICU+6jQY21a69zX4zMlRUxPZ0AJTQgkqAjz1xUpMw6ulTGHtSxAh +fHF0DJ5+gwZcFWMU3OutvDFVGBNQgWMguHvcOGaeb8srsZvS6nzgXZ1S+gBws7tcJrY 6j9Q== X-Gm-Message-State: AOJu0YxJjvuQgAPcKyUjvvJxzUX3HoQlWUHhC7tVWMXs4N+6/PtHqYIo 5IKfj65f25HmqWVwIvmAkWNH5OU4v9jbFk26nbX82dKti/KCBjIgNOfqiBJDYIjPX+M= X-Gm-Gg: ATEYQzzWr6ZoMRckkL6hzjlquQkM23/rT5jVCLtYGVxRHNpffBOWm5tZZLw/swOWqZJ HesqlYo5mUQ/qn/a/sHFQgiQOgOGA/gxp7eOCvVUhBOj7VM4CS3QGY2Als7g5Xj3E3YieteVCyX 3/6IvsRSq8VIxUJ4tGBZDvOBfd0/QrAr7cugr2QofOzU2JmGMvT+TZxX/6FOm+eyikkCADe/9oY qKNEtq/Rc09NE+keUL5Px4ttz1LuNv2E4G61qmOEWZ0u235bFqfNnolv2mRyMxWHZ4GSiqnkri2 7J+3MvESxAB2dW8VsZNvO/+3Cr1RksDz9FZg7QzjvZIB99xazVFog2udCvfN7U5XXExssvxFoXK +u/P3kIl+YafkPMdvLpe9GRk8+U6G+sC6Ay+h6akjAP5aqHTc/lvkYUbZ3JBj07VK7/wD4+mvyX AKvecwC3+FYJF4+bF6mLg0/+6Tg34eDUpaeVggZpREmNSNWEXW X-Received: by 2002:a05:600c:5250:b0:485:9a50:338d with SMTP id 5b1f17b1804b1-486fedab419mr7310045e9.3.1773951950003; Thu, 19 Mar 2026 13:25:50 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.48 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:49 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 32/55] drivers: hv: dxgkrnl: Use tracing instead of dev_dbg Date: Thu, 19 Mar 2026 20:24:46 +0000 Message-ID: <20260319202509.63802-33-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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/dxgadapte= r.c index 236febbc6fca..3d8bec295b87 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -18,8 +18,8 @@ =20 #include "dxgkrnl.h" =20 -#undef pr_fmt -#define pr_fmt(fmt) "dxgk: " fmt +#undef dev_fmt +#define dev_fmt(fmt) "dxgk: " fmt =20 int dxgadapter_set_vmbus(struct dxgadapter *adapter, struct hv_device *hde= v) { 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 =20 +#undef dev_fmt +#define dev_fmt(fmt) "dxgk: " fmt + /* * Interface from dxgglobal */ @@ -442,7 +445,7 @@ const struct file_operations dxgk_fops =3D { #define DXGK_VMBUS_HOSTCAPS_OFFSET (DXGK_VMBUS_VGPU_LUID_OFFSET + \ sizeof(struct winluid)) =20 -/* 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)) =20 diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.c index 5de3f8ccb448..afef196c0588 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -13,8 +13,8 @@ =20 #include "dxgkrnl.h" =20 -#undef pr_fmt -#define pr_fmt(fmt) "dxgk: " fmt +#undef dev_fmt +#define dev_fmt(fmt) "dxgk: " fmt =20 /* * Creates a new dxgprocess object @@ -248,7 +248,7 @@ struct dxgadapter *dxgprocess_adapter_by_handle(struct = dxgprocess *process, HMGRENTRY_TYPE_DXGADAPTER, handle); if (adapter =3D=3D 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) =3D=3D 0) { DXG_ERR("failed to acquire adapter reference"); adapter =3D 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" =20 -#undef pr_fmt -#define pr_fmt(fmt) "dxgk: " fmt +#undef dev_fmt +#define dev_fmt(fmt) "dxgk: " fmt =20 #define RING_BUFSIZE (256 * 1024) =20 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" =20 -#undef pr_fmt -#define pr_fmt(fmt) "dxgk: " fmt +#undef dev_fmt +#define dev_fmt(fmt) "dxgk: " fmt =20 const struct d3dkmthandle zerohandle; =20 @@ -90,29 +90,29 @@ static bool is_handle_valid(struct hmgrtable *table, st= ruct d3dkmthandle h, struct hmgrentry *entry; =20 if (index >=3D table->table_size) { - DXG_ERR("Invalid index %x %d", h.v, index); + DXG_TRACE("Invalid index %x %d", h.v, index); return false; } =20 entry =3D &table->entry_table[index]; if (unique !=3D 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; } =20 if (entry->destroyed && !ignore_destroyed) { - DXG_ERR("Invalid destroyed value"); + DXG_TRACE("Invalid destroyed value"); return false; } =20 if (entry->type =3D=3D 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; } =20 if (t !=3D HMGRENTRY_TYPE_FREE && t !=3D 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; } =20 @@ -500,7 +500,7 @@ void *hmgrtable_get_object_by_type(struct hmgrtable *ta= ble, 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" =20 -#undef pr_fmt -#define pr_fmt(fmt) "dxgk: " fmt +#undef dev_fmt +#define dev_fmt(fmt) "dxgk: " fmt =20 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) =20 cleanup: =20 - DXG_TRACE("ioctl: %s %d", errorstr(ret), ret); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); return ret; } =20 @@ -5242,7 +5242,7 @@ static int dxgk_ioctl(struct file *f, unsigned int p1= , unsigned long p2) int status; struct dxgprocess *process; =20 - if (code < 1 || code >=3D ARRAY_SIZE(ioctls)) { + if (code < 1 || code >=3D 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" =20 -#undef pr_fmt -#define pr_fmt(fmt) "dxgk: " fmt +#undef dev_fmt +#define dev_fmt(fmt) "dxgk: " fmt =20 u16 *wcsncpy(u16 *dest, const u16 *src, size_t n) { From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2B3B03FD137 for ; Thu, 19 Mar 2026 20:25:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951958; cv=none; b=WDw4q/Vqc72F5qK/9pxzY/0qGNrqmJRIj4xEdiSd/vNc3tQdKv/ly8XxwdU+TpzwUP1eB1NXr0dVFNsj+C5gPXy0CacxLUasnooVNNHhV2fzYLAxvaUp/jCFDyXDrW1BuC43TCHUkbm/ztxKblDqy2hxn+xZO13UpAIfsD9TSUI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951958; c=relaxed/simple; bh=uKmGbF8rvOyRqcvPuqwiscaTDoUHnF8QP9h0iffHXoM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=u2APj4an7Vuspw9pJgDaEiioJkvJ2nAuRzJAP6DmeSgxgsYcPCKjJpr6MWhfKYcQ02um9xiJCKtxk77xUPBAvid0lEl/LGh88LFZ9MiWOESkWtzJGIf3hTOBcEJUEUAUKz76Y/embCaK4tDOgVoF38+gWDOhJEXEB3R73OZOyPQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=XOPTdAuT; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XOPTdAuT" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-439bcec8613so990833f8f.3 for ; Thu, 19 Mar 2026 13:25:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951951; x=1774556751; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/VNqCL1U0CSB7nYmpRQ+tYoJD+LmgwpsnfIU7ZhvbLU=; b=XOPTdAuT07Iie5UCIJun/NM8WiMhgjPSRW1e9cptlUOgiP8Jf/db5tqdcNCV8GxE1H MaQ0ATr5vp9wrSI2IbClMlb9qv088iPEsJRyGnb9oYz32vJ0CUJwms/7zvV7Btr3ll+H qJdLuf6JD8TQCRMeSLTi1qnLnD6+Uy50h/99viFqquqs7g32QYM/V+E6TFiGOJ/00GXg evfG5i0x3zded3BqyLwa8J9lwyOSY2NWc56yfTXVEt0TNeNUmmNF9pWkuCvBPBei9Fy5 230oQWQjEdTIubn/2/pxvGbcGQbtpfC5xymgL/hyqIqfON2uqf71XcEGUr/ofonJE3Qs nrdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951951; x=1774556751; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=/VNqCL1U0CSB7nYmpRQ+tYoJD+LmgwpsnfIU7ZhvbLU=; b=FiJDpuJBqAcuz3QU6tqxq1BVIa/2sTshdwByK4BVHMC6MIaD9+OrD+8V7PAVV2VG/7 xM+GTQbwvRA8LK9QkdbgtLX6B8UnWBmWmU9GFqTYh6FICxZYWwDnJ226wLN/nK+7Dqkk Y5i6cXRXsYg8fGu0SWbTUtuPZJjQibt7MgZyxoKF7x440uXW7Rg4QqN6vPj7vSu5/fFl g5rboSQ3BrBTo7Zt/V6FkQp1FGdmZBCeV/qkFjRMA2u6gf2diQmfvXsrA0PJChGyaeMG HWcx8Hq8No4qMK2+6KxN7mS+9CEUzCTKgE8VRTfmLG6cs8S2BxAh2OkuNlvOaZsZiN/m 3Vlw== X-Gm-Message-State: AOJu0YwAIwLuUTE4XspVsShoRW0O+2fkzpCSPYhmsqRUTcXYyLQ3eV8b nprZKFuPAteiweieTTnEA3iPPl3l/dPhL+cQQ26iEGOE58RKZj79VGAk X-Gm-Gg: ATEYQzybPfZqbl32Kp+OTcnxPidPinvk3kr6KS0BkmG2drz9T/WjbFUboMmbwafOjuk ipUaCH/EpTEWzIdfjF9nj6lDRFKIY7bn7XBvMWzyviN4Q2q+2enoI8XpnFi26TDgJnIDXml1PTU PAWnExBFFzYR6jVoxFEAsg/5D4VZC0GidnsQyPnGbsPS7zgCzk4MXb+raKtsbMDQUIY79HOMCmQ NZbIbkMA0TPIT9i9XJHud2ZJNA54mj9bVEC/BCCejJ+ID+8qo2L9bnqv6sqiFQNw0ldDbr9Nt06 VrUms19IApSq/bwHJbPchrlt8ZIpqQWMnelxyWMAGq/gzXAWA2UiTd1KRAHkk+ZUw8tnjxkSWDY uowECiTyszV4nOFx55cF/Dviq9doHQSY5EzJlxF7vkfeX0o01mT+mXa/2zUr9e0spSYNhY+AfSJ U69UBZM36XmXP4bhzbuSHdsAPpxa2FVy25Xzs7KtSE/p0dMgz2 X-Received: by 2002:a05:6000:2c0e:b0:43b:410d:c4b2 with SMTP id ffacd0b85a97d-43b6427d238mr1196798f8f.29.1773951951175; Thu, 19 Mar 2026 13:25:51 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.50 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:50 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 33/55] drivers: hv: dxgkrnl: Implement D3DKMTWaitSyncFile Date: Thu, 19 Mar 2026 20:24:47 +0000 Message-ID: <20260319202509.63802-34-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 dxgsharedsync= object *sharedsyncobj, struct dxgsyncobject *syncobj); void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *sharedsyn= cobj, struct dxgsyncobject *syncobj); +int dxgsharedsyncobj_get_host_nt_handle(struct dxgsharedsyncobject *syncob= j, + struct dxgprocess *process, + struct d3dkmthandle objecthandle); +void dxgsharedsyncobj_put(struct dxgsharedsyncobject *syncobj); =20 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); } =20 -static void signal_dma_fence(struct dxghostevent *eventhdr) +static void dxg_signal_dma_fence(struct dxghostevent *eventhdr) { struct dxgsyncpoint *event =3D (struct dxgsyncpoint *)eventhdr; =20 + 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 =3D=3D dxghostevent_cpu_event) signal_host_cpu_event(event); else if (event->event_type =3D=3D 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 =3D=3D current->tgid) { if (kref_get_unless_zero(&entry->process_kref)) { process =3D 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; =20 kref_put(&process->process_kref, dxgprocess_release); + kref_put(&process->process_mem_kref, dxgprocess_mem_release); =20 f->private_data =3D NULL; return 0; diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgproces= s.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); =20 mutex_lock(&dxgglobal->plistmutex); list_add_tail(&process->plistentry, @@ -117,8 +118,17 @@ void dxgprocess_release(struct kref *refcount) =20 dxgprocess_destroy(process); =20 - if (process->host_handle.v) + if (process->host_handle.v) { dxgvmb_send_destroy_process(process->host_handle); + process->host_handle.v =3D 0; + } +} + +void dxgprocess_mem_release(struct kref *refcount) +{ + struct dxgprocess *process; + + process =3D container_of(refcount, struct dxgprocess, process_mem_kref); kfree(process); } =20 diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.c b/drivers/hv/dxgkrnl/dxgsyncf= ile.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 */ =20 #include @@ -45,12 +59,15 @@ int dxgkio_create_sync_file(struct dxgprocess *process,= void *__user inargs) struct d3dkmt_createsyncfile args; struct dxgsyncpoint *pt =3D NULL; int ret =3D 0; - int fd =3D get_unused_fd_flags(O_CLOEXEC); + int fd; struct sync_file *sync_file =3D NULL; struct dxgdevice *device =3D NULL; struct dxgadapter *adapter =3D NULL; + struct dxgsyncobject *syncobj =3D NULL; struct d3dkmt_waitforsynchronizationobjectfromcpu waitargs =3D {}; + bool device_lock_acquired =3D false; =20 + fd =3D get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { DXG_ERR("get_unused_fd_flags failed: %d", fd); ret =3D fd; @@ -74,9 +91,9 @@ int dxgkio_create_sync_file(struct dxgprocess *process, v= oid *__user inargs) ret =3D dxgdevice_acquire_lock_shared(device); if (ret < 0) { DXG_ERR("dxgdevice_acquire_lock_shared failed"); - device =3D NULL; goto cleanup; } + device_lock_acquired =3D true; =20 adapter =3D device->adapter; ret =3D 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); =20 + hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED); + syncobj =3D hmgrtable_get_object(&process->handle_table, + args.monitored_fence); + if (syncobj =3D=3D NULL) { + DXG_ERR("invalid syncobj handle %x", args.monitored_fence.v); + ret =3D -EINVAL; + } else { + if (syncobj->shared) { + kref_get(&syncobj->syncobj_kref); + pt->shared_syncobj =3D syncobj->shared_owner; + } + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED); + + if (pt->shared_syncobj) { + ret =3D dxgsharedsyncobj_get_host_nt_handle(pt->shared_syncobj, + process, + args.monitored_fence); + if (ret) + pt->shared_syncobj =3D NULL; + } + if (ret) + goto cleanup; + waitargs.device =3D args.device; waitargs.object_count =3D 1; waitargs.objects =3D &args.monitored_fence; @@ -132,10 +173,15 @@ int dxgkio_create_sync_file(struct dxgprocess *proces= s, void *__user inargs) fd_install(fd, sync_file->file); =20 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 *proces= s, void *__user inargs) return ret; } =20 +int dxgkio_open_syncobj_from_syncfile(struct dxgprocess *process, + void *__user inargs) +{ + struct d3dkmt_opensyncobjectfromsyncfile args; + int ret =3D 0; + struct dxgsyncpoint *pt =3D NULL; + struct dma_fence *dmafence =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct dxgsyncobject *syncobj =3D NULL; + struct d3dddi_synchronizationobject_flags flags =3D { }; + struct d3dkmt_opensyncobjectfromnthandle2 openargs =3D { }; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EFAULT; + goto cleanup; + } + + dmafence =3D sync_file_get_fence(args.sync_file_handle); + if (dmafence =3D=3D NULL) { + DXG_ERR("failed to get dmafence from handle: %llx", + args.sync_file_handle); + ret =3D -EINVAL; + goto cleanup; + } + pt =3D to_syncpoint(dmafence); + if (pt->shared_syncobj =3D=3D NULL) { + DXG_ERR("Sync object is not shared"); + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + DXG_ERR("dxgprocess_device_by_handle failed"); + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + DXG_ERR("dxgdevice_acquire_lock_shared failed"); + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + goto cleanup; + } + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + DXG_ERR("dxgadapter_acquire_lock_shared failed"); + adapter =3D NULL; + goto cleanup; + } + + flags.shared =3D 1; + flags.nt_security_sharing =3D 1; + syncobj =3D dxgsyncobject_create(process, device, adapter, + _D3DDDI_MONITORED_FENCE, flags); + if (syncobj =3D=3D NULL) { + DXG_ERR("failed to create sync object"); + ret =3D -ENOMEM; + goto cleanup; + } + dxgsharedsyncobj_add_syncobj(pt->shared_syncobj, syncobj); + + /* Open the shared syncobj to get a local handle */ + + openargs.device =3D device->handle; + openargs.flags.shared =3D 1; + openargs.flags.nt_security_sharing =3D 1; + openargs.flags.no_signal =3D 1; + + ret =3D 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 =3D hmgrtable_assign_handle(&process->handle_table, + syncobj, + HMGRENTRY_TYPE_DXGSYNCOBJECT, + openargs.sync_object); + if (ret =3D=3D 0) { + syncobj->handle =3D openargs.sync_object; + kref_get(&syncobj->syncobj_kref); + } + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); + + args.syncobj =3D openargs.sync_object; + args.fence_value =3D pt->fence_value; + args.fence_value_cpu_va =3D openargs.monitored_fence.fence_value_cpu_va; + args.fence_value_gpu_va =3D openargs.monitored_fence.fence_value_gpu_va; + + ret =3D copy_to_user(inargs, &args, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy output args"); + ret =3D -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 =3D NULL; + int ret =3D 0; + struct dxgsyncpoint *pt =3D NULL; + struct dxgdevice *device =3D NULL; + struct dxgadapter *adapter =3D NULL; + struct d3dkmthandle syncobj_handle =3D {}; + bool device_lock_acquired =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EFAULT; + goto cleanup; + } + + dmafence =3D sync_file_get_fence(args.sync_file_handle); + if (dmafence =3D=3D NULL) { + DXG_ERR("failed to get dmafence from handle: %llx", + args.sync_file_handle); + ret =3D -EINVAL; + goto cleanup; + } + pt =3D to_syncpoint(dmafence); + + device =3D dxgprocess_device_by_object_handle(process, + HMGRENTRY_TYPE_DXGCONTEXT, + args.context); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + DXG_ERR("dxgdevice_acquire_lock_shared failed"); + device =3D NULL; + goto cleanup; + } + device_lock_acquired =3D true; + + adapter =3D device->adapter; + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + DXG_ERR("dxgadapter_acquire_lock_shared failed"); + adapter =3D NULL; + goto cleanup; + } + + /* Open the shared syncobj to get a local handle */ + if (pt->shared_syncobj =3D=3D NULL) { + DXG_ERR("Sync object is not shared"); + goto cleanup; + } + ret =3D 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 =3D 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 =3D 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 *fen= ce) struct dxgsyncpoint *syncpoint; =20 syncpoint =3D to_syncpoint(fence); - if (syncpoint) { - if (syncpoint->hdr.event_id) - dxgglobal_get_host_event(syncpoint->hdr.event_id); - kfree(syncpoint); - } + if (syncpoint =3D=3D 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); } =20 static bool dxgdmafence_signaled(struct dma_fence *fence) diff --git a/drivers/hv/dxgkrnl/dxgsyncfile.h b/drivers/hv/dxgkrnl/dxgsyncf= ile.h index 207ef9b30f67..292b7f718987 100644 --- a/drivers/hv/dxgkrnl/dxgsyncfile.h +++ b/drivers/hv/dxgkrnl/dxgsyncfile.h @@ -17,10 +17,13 @@ #include =20 int dxgkio_create_sync_file(struct dxgprocess *process, void *__user inarg= s); +int dxgkio_wait_sync_file(struct dxgprocess *process, void *__user inargs); +int dxgkio_open_syncobj_from_syncfile(struct dxgprocess *p, void *__user a= rgs); =20 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; } =20 +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 =3D { }; + int ret; + struct dxgvmbusmsg msg; + struct dxgglobal *dxgglobal =3D dxggbl(); + + ret =3D init_message(&msg, NULL, process, sizeof(*command)); + if (ret) + return ret; + command =3D (void *)msg.msg; + + command_vm_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_OPENSYNCOBJECT, + process->host_handle); + command->device =3D device; + command->global_sync_object =3D host_shared_syncobj; + command->flags.shared =3D 1; + command->flags.nt_security_sharing =3D 1; + command->flags.no_signal =3D 1; + + ret =3D dxgglobal_acquire_channel_lock(); + if (ret < 0) + goto cleanup; + + ret =3D dxgvmb_send_sync_msg(&dxgglobal->channel, msg.hdr, msg.size, + &result, sizeof(result)); + + dxgglobal_release_channel_lock(); + + if (ret < 0) + goto cleanup; + + ret =3D ntstatus2int(result.status); + if (ret < 0) + goto cleanup; + + *syncobj =3D 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 =20 -static int dxgsyncobj_release(struct inode *inode, struct file *file) +void dxgsharedsyncobj_put(struct dxgsharedsyncobject *syncobj) { - struct dxgsharedsyncobject *syncobj =3D 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, struc= t 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 =3D file->private_data; + + dxgsharedsyncobj_put(syncobj); return 0; } =20 @@ -4478,7 +4483,7 @@ dxgkio_get_device_state(struct dxgprocess *process, v= oid *__user inargs) return ret; } =20 -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[] =3D { /* 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}, }; =20 /* 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 */ }; =20 +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) =20 #endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AA5AE3FE347 for ; Thu, 19 Mar 2026 20:25:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951965; cv=none; b=P6g7NLXlQ3s6v7NkUSRKE1wX08/uSR1FCHunjE+xBVDDQ2bxLHcqHUPkC2XOl6GzdRQaBMFubyQAQeRTorIx0kbDA+BZJR1+2eI010PECq0EOltxHW/P2iQS4knioFhlg42d0ICndMHUtFiHaR4SiSzWa2IgpgnLxt/hdcKLlos= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951965; c=relaxed/simple; bh=wQnn+i7HDDPXuej5K3rlTfB9nYZEhWTHsN8WCvRd9cc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JHb+o+o+q4BwbQwBnLBmJtsdBfcUDKGMM6y7qb/wc6kYsl/wgnE2oErRxswz8Aa0GH7AOfKtC31pAYgR31gMZemRfo76stkp+zc5plOFNZqRDxLd0o5w9jvgPbptXxVNMelgJjDWBgLm09fgowdLLQRl0k0fa88bK5c4R2LZJaE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=OtVFUJo4; arc=none smtp.client-ip=209.85.221.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OtVFUJo4" Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-43b4d734678so1373226f8f.1 for ; Thu, 19 Mar 2026 13:25:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951953; x=1774556753; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4d2q8ALa933Eh/PiXW6PrWUfVVovOz9gsGmUizF5y3c=; b=OtVFUJo4ZCnG31ffUpffYpbBnd/19H8Ezkr9XeqC3ejvzBvygYeDI9Xs7zeZEFXiY+ m84TZCx/Yd2REN6Vg2O6M/s7fQEYErfZGzc8JieuFrR6arG61lKT8qlb/hgXh3+3pNsl Vny+a/FQBgMEqsMOcBTc+E0f2aC7tIz0++iM5PjNYw8fSJoIHo3CJK1kx9JBNX+4cnM8 lJ4I8qALtR348ob3Vdz52r1LFzfc9NQSta52y0idHajPw9GY/oHZCfFLabMRUmPDprhH CJNB0GaC4NDUL+5Sj9ufmFMFS9zW5l60Mk7MRdPWi0KPcL1gRzb/JD4S8W8OO+tBX23W jLkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951953; x=1774556753; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=4d2q8ALa933Eh/PiXW6PrWUfVVovOz9gsGmUizF5y3c=; b=YqoRW+JnMctaFXQxF8YmJTWjzVSkMn949f4SGFnh6d2BwVM/EhAwYcAY91YPvu5JJS kPDDisgDExZgkENI56V92GcOnl13UWzsdVxZbN3CeqPA9VLSdyQxI9gfNxQdwzTIOgk3 4+rXWgdewEEi0cz6ue5iBwDmGWBgsvvMXz/2s6lgy29l2Gd7i1wzL3eZ4G+T1bw6Hcaf BXkBJoXGb23gzx2rNH1TSD6dz1zw6NCD50IPybQyJBdxYO+znPKXY9gD4WeUGv6Z4PyC MXD3CQL34Uj3N6908eYyr4gBuG9YD9t3isSh43KgVNWxXAnyiSqcfgmpCoimUW/yE6NA 42LQ== X-Gm-Message-State: AOJu0YwzKxwsMrkLrpoApQauQaaWRHKe0hqx+7Ue+M2+cO6L1/URWaP7 +EYxWqG28ZXYGWDIIBVEt2HE2N+QCI/7PA4f6bqVETLgCD3vf0j4rp8j X-Gm-Gg: ATEYQzxrXudF8VbAQMUjuEpJsUzAM+fvEqr6Gll2fjhxb8bXEBBBNhtMUUEP3u2ym0M YNXO8OE+P1uVnKNWNSbM648Qe9FnlNTZJMuHl/HMTdJ5MVWPn/aoI9gxe0HgtLIfgPHzmOQbLVA Gq2fCSKJ7e3n1A3PDhlAsik+UNFoyr1CVPP08EP0nsuE48XDnxnS9HDPpG3pKeBPGNpZ6ipGjgM 5Zi9eGIe0BfazT9kCxCv4tVHEEPyKnq6QB0YRzyweWCW5wuW0yUh7/x7SvIJS2chc0cCPDPS8SU /Ksz3vovAQGOozS3bPv5SRT8oz7IL8gYFcSgtwco682dkclPQ+lyZXJqCsGGE2b31WzSuUW8Hnk RhgdGMArIv0BJfZ2WGpIT/J16geQXq5lQ2Lhp8phTQB26U3PHO/U1Yh8bNP258YXzPpZFnhADXi hlcDQjn0WasZLNOr0UKbw4hFjyVih0G+HcPImZuvE4CouR38Gb X-Received: by 2002:a05:6000:310e:b0:43b:564d:c11d with SMTP id ffacd0b85a97d-43b64234717mr1296643f8f.11.1773951952430; Thu, 19 Mar 2026 13:25:52 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.51 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:51 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 34/55] drivers: hv: dxgkrnl: Improve tracing and return values from copy from user Date: Thu, 19 Mar 2026 20:24:48 +0000 Message-ID: <20260319202509.63802-35-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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) =20 -#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) =20 #else =20 #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) =20 #endif /* DEBUG */ =20 +#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); =20 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/dxgsyncf= ile.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 =20 -#ifdef DEBUG -static char *errorstr(int ret) -{ - return ret < 0 ? "err" : ""; -} -#endif - static const struct dma_fence_ops dxgdmafence_ops; =20 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 >=3D 0) put_unused_fd(fd); } - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -317,7 +310,7 @@ int dxgkio_open_syncobj_from_syncfile(struct dxgprocess= *process, kref_put(&device->device_kref, dxgdevice_release); } =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -415,7 +408,7 @@ int dxgkio_wait_sync_file(struct dxgprocess *process, v= oid *__user inargs) if (dmafence) dma_fence_put(dmafence); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; dxgvmb_send_destroy_context(adapter, process, context); context.v =3D 0; @@ -1365,7 +1365,7 @@ copy_private_data(struct d3dkmt_createallocation *arg= s, args->private_runtime_data_size); if (ret) { DXG_ERR("failed to copy runtime data"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } private_data_dest +=3D args->private_runtime_data_size; @@ -1385,7 +1385,7 @@ copy_private_data(struct d3dkmt_createallocation *arg= s, args->priv_drv_data_size); if (ret) { DXG_ERR("failed to copy private data"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } private_data_dest +=3D args->priv_drv_data_size; @@ -1406,7 +1406,7 @@ copy_private_data(struct d3dkmt_createallocation *arg= s, input_alloc->priv_drv_data_size); if (ret) { DXG_ERR("failed to copy alloc data"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } private_data_dest +=3D 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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } alloc_private_data +=3D 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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -1961,7 +1961,7 @@ int dxgvmb_send_query_clock_calibration(struct dxgpro= cess *process, sizeof(result.clock_data)); if (ret) { DXG_ERR("failed to copy clock data"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D ntstatus2int(result.status); @@ -2041,7 +2041,7 @@ int dxgvmb_send_query_alloc_residency(struct dxgproce= ss *process, alloc_size); if (ret) { DXG_ERR("failed to copy alloc handles"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } } @@ -2059,7 +2059,7 @@ int dxgvmb_send_query_alloc_residency(struct dxgproce= ss *process, result_allocation_size); if (ret) { DXG_ERR("failed to copy residency status"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D copy_to_user(&output->current_usage, &result.current_usage, sizeof(output->current_usage)); if (ret) { DXG_ERR("failed to copy current usage"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D 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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D 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 =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -2229,7 +2229,7 @@ int dxgvmb_send_get_device_state(struct dxgprocess *p= rocess, ret =3D copy_to_user(output, &result.args, sizeof(result.args)); if (ret) { DXG_ERR("failed to copy output args"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 if (args->state_type =3D=3D _D3DKMT_DEVICESTATE_EXECUTION) @@ -2404,7 +2404,7 @@ int dxgvmb_send_make_resident(struct dxgprocess *proc= ess, sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to copy alloc handles"); - ret =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } command_vgpu_to_host_init2(&command->hdr, @@ -2502,14 +2502,14 @@ int dxgvmb_send_submit_command(struct dxgprocess *p= rocess, hbufsize); if (ret) { DXG_ERR(" failed to copy history buffer"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D 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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2671,7 +2671,7 @@ int dxgvmb_send_update_gpu_va(struct dxgprocess *proc= ess, op_size); if (ret) { DXG_ERR("failed to copy operations"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2751,7 +2751,7 @@ dxgvmb_send_create_sync_object(struct dxgprocess *pro= cess, sizeof(u64)); if (ret) { DXG_ERR("failed to read fence"); - ret =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } current_pos +=3D 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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } current_pos +=3D 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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } } @@ -2898,7 +2898,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgproces= s *process, ret =3D copy_from_user(current_pos, args->objects, object_size); if (ret) { DXG_ERR("failed to copy objects"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } current_pos +=3D object_size; @@ -2906,7 +2906,7 @@ int dxgvmb_send_wait_sync_object_cpu(struct dxgproces= s *process, fence_size); if (ret) { DXG_ERR("failed to copy fences"); - ret =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; alloc->cpu_address_refcount--; if (alloc->cpu_address_refcount =3D=3D 0) { dxg_unmap_iospace(alloc->cpu_address, @@ -3119,7 +3119,7 @@ int dxgvmb_send_update_alloc_property(struct dxgproce= ss *process, sizeof(u64)); if (ret1) { DXG_ERR("failed to copy paging fence"); - ret =3D -EINVAL; + ret =3D -EFAULT; } } cleanup: @@ -3204,14 +3204,14 @@ int dxgvmb_send_set_allocation_priority(struct dxgp= rocess *process, alloc_size); if (ret) { DXG_ERR("failed to copy alloc handle"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D copy_from_user((u8 *) allocations + alloc_size, args->priorities, priority_size); if (ret) { DXG_ERR("failed to copy alloc priority"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3277,7 +3277,7 @@ int dxgvmb_send_get_allocation_priority(struct dxgpro= cess *process, alloc_size); if (ret) { DXG_ERR("failed to copy alloc handles"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3296,7 +3296,7 @@ int dxgvmb_send_get_allocation_priority(struct dxgpro= cess *process, priority_size); if (ret) { DXG_ERR("failed to copy priorities"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -3402,7 +3402,7 @@ int dxgvmb_send_offer_allocations(struct dxgprocess *= process, } if (ret) { DXG_ERR("failed to copy input handles"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3457,7 +3457,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess= *process, } if (ret) { DXG_ERR("failed to copy input handles"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3480,7 +3480,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess= *process, args->allocation_count); if (ret) { DXG_ERR("failed to copy results"); - ret =3D -EINVAL; + ret =3D -EFAULT; } } =20 @@ -3559,7 +3559,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *pro= cess, args->priv_drv_data_size); if (ret) { DXG_ERR("failed to copy private data"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } } @@ -3604,7 +3604,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *pro= cess, sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to copy hwqueue handle"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D copy_to_user(&inargs->queue_progress_fence, @@ -3612,7 +3612,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *pro= cess, sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to progress fence"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D copy_to_user(&inargs->queue_progress_fence_cpu_va, @@ -3620,7 +3620,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *pro= cess, sizeof(inargs->queue_progress_fence_cpu_va)); if (ret) { DXG_ERR("failed to copy fence cpu va"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D copy_to_user(&inargs->queue_progress_fence_gpu_va, @@ -3628,7 +3628,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *pro= cess, sizeof(u64)); if (ret) { DXG_ERR("failed to copy fence gpu va"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } if (args->priv_drv_data_size) { @@ -3637,7 +3637,7 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *pro= cess, args->priv_drv_data_size); if (ret) { DXG_ERR("failed to copy private data"); - ret =3D -EINVAL; + ret =3D -EFAULT; } } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -3791,7 +3791,7 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgproc= ess *process, primaries_size); if (ret) { DXG_ERR("failed to copy primaries handles"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } } @@ -3801,7 +3801,7 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgproc= ess *process, args->priv_drv_data_size); if (ret) { DXG_ERR("failed to copy primaries data"); - ret =3D -EINVAL; + ret =3D -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; }; =20 -#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 dxgproc= ess *process, ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("Faled to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -129,7 +122,7 @@ static int dxgkio_open_adapter_from_luid(struct dxgproc= ess *process, &args.adapter_handle, sizeof(struct d3dkmthandle)); if (ret) - ret =3D -EINVAL; + ret =3D -EFAULT; } adapter =3D entry; } @@ -150,7 +143,7 @@ static int dxgkio_open_adapter_from_luid(struct dxgproc= ess *process, if (ret < 0) dxgprocess_close_adapter(process, args.adapter_handle); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -173,7 +166,7 @@ static int dxgkio_query_statistics(struct dxgprocess *p= rocess, ret =3D copy_from_user(args, inargs, sizeof(*args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -199,7 +192,7 @@ static int dxgkio_query_statistics(struct dxgprocess *p= rocess, ret =3D copy_to_user(inargs, args, sizeof(*args)); if (ret) { DXG_ERR("failed to copy args"); - ret =3D -EINVAL; + ret =3D -EFAULT; } } dxgadapter_release_lock_shared(adapter); @@ -209,7 +202,7 @@ static int dxgkio_query_statistics(struct dxgprocess *p= rocess, if (args) vfree(args); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -233,7 +226,7 @@ dxgkp_enum_adapters(struct dxgprocess *process, &dxgglobal->num_adapters, sizeof(u32)); if (ret) { DXG_ERR("copy_to_user faled"); - ret =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D copy_to_user(info_out, info, sizeof(info[0]) * adapter_count); if (ret) { DXG_ERR("failed to copy adapter info"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -326,7 +319,7 @@ dxgkp_enum_adapters(struct dxgprocess *process, if (adapters) vfree(adapters); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -437,7 +430,7 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *= __user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -447,7 +440,7 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *= __user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy args to user"); - ret =3D -EINVAL; + ret =3D -EFAULT; } goto cleanup; } @@ -508,14 +501,14 @@ dxgkio_enum_adapters(struct dxgprocess *process, void= *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy args to user"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } ret =3D copy_to_user(args.adapters, info, sizeof(info[0]) * args.num_adapters); if (ret) { DXG_ERR("failed to copy adapter info to user"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -536,7 +529,7 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *= __user inargs) if (adapters) vfree(adapters); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -549,7 +542,7 @@ dxgkio_enum_adapters3(struct dxgprocess *process, void = *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -561,7 +554,7 @@ dxgkio_enum_adapters3(struct dxgprocess *process, void = *__user inargs) =20 cleanup: =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -574,7 +567,7 @@ dxgkio_close_adapter(struct dxgprocess *process, void *= __user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -584,7 +577,7 @@ dxgkio_close_adapter(struct dxgprocess *process, void *= __user inargs) =20 cleanup: =20 - DXG_TRACE("ioctl: %s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -598,7 +591,7 @@ dxgkio_query_adapter_info(struct dxgprocess *process, v= oid *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -630,7 +623,7 @@ dxgkio_query_adapter_info(struct dxgprocess *process, v= oid *__user inargs) if (adapter) kref_put(&adapter->adapter_kref, dxgadapter_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -647,7 +640,7 @@ dxgkio_create_device(struct dxgprocess *process, void *= __user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -709,7 +702,7 @@ dxgkio_create_device(struct dxgprocess *process, void *= __user inargs) if (adapter) kref_put(&adapter->adapter_kref, dxgadapter_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -724,7 +717,7 @@ dxgkio_destroy_device(struct dxgprocess *process, void = *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -756,7 +749,7 @@ dxgkio_destroy_device(struct dxgprocess *process, void = *__user inargs) =20 cleanup: =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -774,7 +767,7 @@ dxgkio_create_context_virtual(struct dxgprocess *proces= s, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -824,7 +817,7 @@ dxgkio_create_context_virtual(struct dxgprocess *proces= s, void *__user inargs) sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to copy context handle"); - ret =3D -EINVAL; + ret =3D -EFAULT; } } else { DXG_ERR("invalid host handle"); @@ -851,7 +844,7 @@ dxgkio_create_context_virtual(struct dxgprocess *proces= s, void *__user inargs) kref_put(&device->device_kref, dxgdevice_release); } =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -868,7 +861,7 @@ dxgkio_destroy_context(struct dxgprocess *process, void= *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -920,7 +913,7 @@ dxgkio_destroy_context(struct dxgprocess *process, void= *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %s %d", errorstr(ret), __func__, ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -938,7 +931,7 @@ dxgkio_create_hwqueue(struct dxgprocess *process, void = *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -1002,7 +995,7 @@ dxgkio_create_hwqueue(struct dxgprocess *process, void= *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -1019,7 +1012,7 @@ static int dxgkio_destroy_hwqueue(struct dxgprocess *= process, ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -1070,7 +1063,7 @@ static int dxgkio_destroy_hwqueue(struct dxgprocess *= process, if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -1088,7 +1081,7 @@ dxgkio_create_paging_queue(struct dxgprocess *process= , void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -1128,7 +1121,7 @@ dxgkio_create_paging_queue(struct dxgprocess *process= , void *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -1169,7 +1162,7 @@ dxgkio_create_paging_queue(struct dxgprocess *process= , void *__user inargs) kref_put(&device->device_kref, dxgdevice_release); } =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -1186,7 +1179,7 @@ dxgkio_destroy_paging_queue(struct dxgprocess *proces= s, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -1247,7 +1240,7 @@ dxgkio_destroy_paging_queue(struct dxgprocess *proces= s, void *__user inargs) kref_put(&device->device_kref, dxgdevice_release); } =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -1351,7 +1344,7 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } if (standard_alloc.type =3D=3D @@ -1556,7 +1549,7 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) if (ret) { DXG_ERR( "failed to copy runtime data"); - ret =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } } @@ -1733,7 +1726,7 @@ dxgkio_create_allocation(struct dxgprocess *process, = void *__user inargs) kref_put(&device->device_kref, dxgdevice_release); } =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -1793,7 +1786,7 @@ dxgkio_destroy_allocation(struct dxgprocess *process,= void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } } @@ -1962,7 +1955,7 @@ dxgkio_destroy_allocation(struct dxgprocess *process,= void *__user inargs) if (allocs) vfree(allocs); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -1978,7 +1971,7 @@ dxgkio_make_resident(struct dxgprocess *process, void= *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2041,7 +2034,7 @@ dxgkio_make_resident(struct dxgprocess *process, void= *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); =20 return ret; } @@ -2058,7 +2051,7 @@ dxgkio_evict(struct dxgprocess *process, void *__user= inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; } cleanup: =20 @@ -2099,7 +2092,7 @@ dxgkio_evict(struct dxgprocess *process, void *__user= inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2114,7 +2107,7 @@ dxgkio_offer_allocations(struct dxgprocess *process, = void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2153,7 +2146,7 @@ dxgkio_offer_allocations(struct dxgprocess *process, = void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2169,7 +2162,7 @@ dxgkio_reclaim_allocations(struct dxgprocess *process= , void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2212,7 +2205,7 @@ dxgkio_reclaim_allocations(struct dxgprocess *process= , void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2227,7 +2220,7 @@ dxgkio_submit_command(struct dxgprocess *process, voi= d *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2280,7 +2273,7 @@ dxgkio_submit_command(struct dxgprocess *process, voi= d *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2296,7 +2289,7 @@ dxgkio_submit_command_to_hwqueue(struct dxgprocess *p= rocess, ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2336,7 +2329,7 @@ dxgkio_submit_command_to_hwqueue(struct dxgprocess *p= rocess, if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2352,7 +2345,7 @@ dxgkio_submit_signal_to_hwqueue(struct dxgprocess *pr= ocess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2376,7 +2369,7 @@ dxgkio_submit_signal_to_hwqueue(struct dxgprocess *pr= ocess, void *__user inargs) sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to copy hwqueue handle"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2410,7 +2403,7 @@ dxgkio_submit_signal_to_hwqueue(struct dxgprocess *pr= ocess, void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2428,7 +2421,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2447,7 +2440,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(objects, args.objects, object_size); if (ret) { DXG_ERR("failed to copy objects"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2460,7 +2453,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(fences, args.fence_values, object_size); if (ret) { DXG_ERR("failed to copy fence values"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2494,7 +2487,7 @@ dxgkio_submit_wait_to_hwqueue(struct dxgprocess *proc= ess, void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2510,7 +2503,7 @@ dxgkio_map_gpu_va(struct dxgprocess *process, void *_= _user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2561,7 +2554,7 @@ dxgkio_map_gpu_va(struct dxgprocess *process, void *_= _user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2577,7 +2570,7 @@ dxgkio_reserve_gpu_va(struct dxgprocess *process, voi= d *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2614,7 +2607,7 @@ dxgkio_reserve_gpu_va(struct dxgprocess *process, voi= d *__user inargs) sizeof(args.virtual_address)); if (ret) { DXG_ERR("failed to copy VA to user"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -2624,7 +2617,7 @@ dxgkio_reserve_gpu_va(struct dxgprocess *process, voi= d *__user inargs) kref_put(&adapter->adapter_kref, dxgadapter_release); } =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2638,7 +2631,7 @@ dxgkio_free_gpu_va(struct dxgprocess *process, void *= __user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2680,7 +2673,7 @@ dxgkio_update_gpu_va(struct dxgprocess *process, void= *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -2734,7 +2727,7 @@ dxgkio_create_sync_object(struct dxgprocess *process,= void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2808,7 +2801,7 @@ dxgkio_create_sync_object(struct dxgprocess *process,= void *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy output args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2842,7 +2835,7 @@ dxgkio_create_sync_object(struct dxgprocess *process,= void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2856,7 +2849,7 @@ dxgkio_destroy_sync_object(struct dxgprocess *process= , void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2885,7 +2878,7 @@ dxgkio_destroy_sync_object(struct dxgprocess *process= , void *__user inargs) =20 cleanup: =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -2906,7 +2899,7 @@ dxgkio_open_sync_object_nt(struct dxgprocess *process= , void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -2995,7 +2988,7 @@ dxgkio_open_sync_object_nt(struct dxgprocess *process= , void *__user inargs) if (ret =3D=3D 0) goto success; DXG_ERR("failed to copy output args"); - ret =3D -EINVAL; + ret =3D -EFAULT; =20 cleanup: =20 @@ -3020,7 +3013,7 @@ dxgkio_open_sync_object_nt(struct dxgprocess *process= , void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3041,7 +3034,7 @@ dxgkio_signal_sync_object(struct dxgprocess *process,= void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3129,7 +3122,7 @@ dxgkio_signal_sync_object(struct dxgprocess *process,= void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3144,7 +3137,7 @@ dxgkio_signal_sync_object_cpu(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } if (args.object_count =3D=3D 0 || @@ -3181,7 +3174,7 @@ dxgkio_signal_sync_object_cpu(struct dxgprocess *proc= ess, void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3199,7 +3192,7 @@ dxgkio_signal_sync_object_gpu(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3240,7 +3233,7 @@ dxgkio_signal_sync_object_gpu(struct dxgprocess *proc= ess, void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3262,7 +3255,7 @@ dxgkio_signal_sync_object_gpu2(struct dxgprocess *pro= cess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3287,7 +3280,7 @@ dxgkio_signal_sync_object_gpu2(struct dxgprocess *pro= cess, void *__user inargs) sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to copy context handle"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3365,7 +3358,7 @@ dxgkio_signal_sync_object_gpu2(struct dxgprocess *pro= cess, void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3380,7 +3373,7 @@ dxgkio_wait_sync_object(struct dxgprocess *process, v= oid *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3418,7 +3411,7 @@ dxgkio_wait_sync_object(struct dxgprocess *process, v= oid *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3439,7 +3432,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *proces= s, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3540,7 +3533,7 @@ dxgkio_wait_sync_object_cpu(struct dxgprocess *proces= s, void *__user inargs) kfree(async_host_event); } =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3563,7 +3556,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proces= s, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3583,7 +3576,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proces= s, void *__user inargs) ret =3D copy_from_user(objects, args.objects, object_size); if (ret) { DXG_ERR("failed to copy objects"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3637,7 +3630,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proces= s, void *__user inargs) object_size); if (ret) { DXG_ERR("failed to copy fences"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } } else { @@ -3673,7 +3666,7 @@ dxgkio_wait_sync_object_gpu(struct dxgprocess *proces= s, void *__user inargs) if (fences && fences !=3D &args.fence_value) vfree(fences); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3690,7 +3683,7 @@ dxgkio_lock2(struct dxgprocess *process, void *__user= inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; } } } @@ -3749,7 +3742,7 @@ dxgkio_lock2(struct dxgprocess *process, void *__user= inargs) kref_put(&device->device_kref, dxgdevice_release); =20 success: - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3766,7 +3759,7 @@ dxgkio_unlock2(struct dxgprocess *process, void *__us= er inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3829,7 +3822,7 @@ dxgkio_unlock2(struct dxgprocess *process, void *__us= er inargs) kref_put(&device->device_kref, dxgdevice_release); =20 success: - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3844,7 +3837,7 @@ dxgkio_update_alloc_property(struct dxgprocess *proce= ss, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3872,7 +3865,7 @@ dxgkio_update_alloc_property(struct dxgprocess *proce= ss, void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -3887,7 +3880,7 @@ dxgkio_mark_device_as_error(struct dxgprocess *proces= s, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } device =3D dxgprocess_device_by_handle(process, args.device); @@ -3908,7 +3901,7 @@ dxgkio_mark_device_as_error(struct dxgprocess *proces= s, 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; } =20 @@ -3923,7 +3916,7 @@ dxgkio_query_alloc_residency(struct dxgprocess *proce= ss, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -3949,7 +3942,7 @@ dxgkio_query_alloc_residency(struct dxgprocess *proce= ss, 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; } =20 @@ -3964,7 +3957,7 @@ dxgkio_set_allocation_priority(struct dxgprocess *pro= cess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } device =3D dxgprocess_device_by_handle(process, args.device); @@ -3984,7 +3977,7 @@ dxgkio_set_allocation_priority(struct dxgprocess *pro= cess, 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; } =20 @@ -3999,7 +3992,7 @@ dxgkio_get_allocation_priority(struct dxgprocess *pro= cess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } device =3D dxgprocess_device_by_handle(process, args.device); @@ -4019,7 +4012,7 @@ dxgkio_get_allocation_priority(struct dxgprocess *pro= cess, 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; } =20 @@ -4069,14 +4062,14 @@ dxgkio_set_context_scheduling_priority(struct dxgpr= ocess *process, ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 ret =3D 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; } =20 @@ -4111,7 +4104,7 @@ get_context_scheduling_priority(struct dxgprocess *pr= ocess, ret =3D copy_to_user(priority, &pri, sizeof(pri)); if (ret) { DXG_ERR("failed to copy priority to user"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -4134,14 +4127,14 @@ dxgkio_get_context_scheduling_priority(struct dxgpr= ocess *process, ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 ret =3D 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; } =20 @@ -4155,14 +4148,14 @@ dxgkio_set_context_process_scheduling_priority(stru= ct dxgprocess *process, ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 ret =3D 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; } =20 @@ -4176,7 +4169,7 @@ dxgkio_get_context_process_scheduling_priority(struct= dxgprocess *process, ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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; } =20 @@ -4199,7 +4192,7 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *p= rocess, void *__user inargs ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4232,7 +4225,7 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *p= rocess, void *__user inargs if (adapter) kref_put(&adapter->adapter_kref, dxgadapter_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -4247,7 +4240,7 @@ dxgkio_query_clock_calibration(struct dxgprocess *pro= cess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4272,7 +4265,7 @@ dxgkio_query_clock_calibration(struct dxgprocess *pro= cess, void *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy output args"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -4295,7 +4288,7 @@ dxgkio_flush_heap_transitions(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4319,7 +4312,7 @@ dxgkio_flush_heap_transitions(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy output args"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -4341,7 +4334,7 @@ dxgkio_escape(struct dxgprocess *process, void *__use= r inargs) =20 ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4367,7 +4360,7 @@ dxgkio_escape(struct dxgprocess *process, void *__use= r 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; } =20 @@ -4382,7 +4375,7 @@ dxgkio_query_vidmem_info(struct dxgprocess *process, = void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4432,7 +4425,7 @@ dxgkio_get_device_state(struct dxgprocess *process, v= oid *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4458,7 +4451,7 @@ dxgkio_get_device_state(struct dxgprocess *process, v= oid *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy args to user"); - ret =3D -EINVAL; + ret =3D -EFAULT; } goto cleanup; } @@ -4590,7 +4583,7 @@ dxgkio_share_objects(struct dxgprocess *process, void= *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4610,7 +4603,7 @@ dxgkio_share_objects(struct dxgprocess *process, void= *__user inargs) ret =3D copy_from_user(handles, args.objects, handle_size); if (ret) { DXG_ERR("failed to copy object handles"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4708,7 +4701,7 @@ dxgkio_share_objects(struct dxgprocess *process, void= *__user inargs) ret =3D copy_to_user(args.shared_handle, &tmp, sizeof(u64)); if (ret) { DXG_ERR("failed to copy shared handle"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -4726,7 +4719,7 @@ dxgkio_share_objects(struct dxgprocess *process, void= *__user inargs) if (resource) kref_put(&resource->resource_kref, dxgresource_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -4742,7 +4735,7 @@ dxgkio_query_resource_info_nt(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -4795,7 +4788,7 @@ dxgkio_query_resource_info_nt(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy output args"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -4807,7 +4800,7 @@ dxgkio_query_resource_info_nt(struct dxgprocess *proc= ess, void *__user inargs) if (device) kref_put(&device->device_kref, dxgdevice_release); =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -4859,7 +4852,7 @@ assign_resource_handles(struct dxgprocess *process, sizeof(open_alloc_info)); if (ret) { DXG_ERR("failed to copy alloc info"); - ret =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -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 =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -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 =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: @@ -5102,7 +5095,7 @@ dxgkio_open_resource_nt(struct dxgprocess *process, v= oid *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -5112,7 +5105,7 @@ dxgkio_open_resource_nt(struct dxgprocess *process, v= oid *__user inargs) =20 cleanup: =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -5125,7 +5118,7 @@ dxgkio_share_object_with_host(struct dxgprocess *proc= ess, void *__user inargs) ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { DXG_ERR("failed to copy input args"); - ret =3D -EINVAL; + ret =3D -EFAULT; goto cleanup; } =20 @@ -5138,12 +5131,12 @@ dxgkio_share_object_with_host(struct dxgprocess *pr= ocess, void *__user inargs) ret =3D copy_to_user(inargs, &args, sizeof(args)); if (ret) { DXG_ERR("failed to copy data to user"); - ret =3D -EINVAL; + ret =3D -EFAULT; } =20 cleanup: =20 - DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + DXG_TRACE_IOCTL_END(ret); return ret; } From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B7D63FE35C for ; Thu, 19 Mar 2026 20:25:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951960; cv=none; b=XIOwsCvfpAIl3is6fk0Uq2Jeg3TjenUWYwvewQzyp29o7yQLaJZnjMyGKREbwuJsfK35WXg5eMjSrIBIwGjWoUHyZpXxwpq6MRVAIqpIdQLjHxVRwxeDuMJiC+K3NCDPGo3vlU8FS4sZPxrmswHwsiJPfvxRxe93iOrgvcJgpMw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951960; c=relaxed/simple; bh=PZhfdkz6l06fsjXhfbGY5sTpwcEke0jta0C1rvcvPOg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jWifNmNtNh/7kaA9RLYF7aRFvqvNYQmyGEJdN9KfpE3VzJNlOSWZhrPfUeVaj8xYZoe3mDLyVBf+B3tEb61ufLnjCD0XAGjq9Tq77jrmc2ESsa/QOCVtDEX7yb6V6hCg6enOvq0evGcWggA+HNhUeQ7mIPPGPVbB/9/EkOFjs/o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=lUR0p8Vx; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lUR0p8Vx" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-43b49819938so713035f8f.0 for ; Thu, 19 Mar 2026 13:25:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951954; x=1774556754; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=i9rYNHxfIvxcKsQ5ZLeeb8g2hhtOSjW/hV2qStJ99hI=; b=lUR0p8VxV4zsNnG1lqlfthJciimVjKCi7azHXERgNIMeFGEsRCU4btg2ReH8Lgd6xL ktPdfmGYD6uV2I3ZqL0ufomjcAqH0YPuVXoWO3dEMFCmNtnEwZNymzv94HIj+uqYW0x7 J8uaRoqPuJA5IsLzazNfz1AN3dFvidUtoKmo3hB7P1qDPRUmJEi7r+c5DAe50/HnePM1 k6exZI/H9dFbLrtFV3olantFSnxONx9CjPtptaU9Bi02RYiUcOp9Fz5B72Ta1UshKT/E kjHnPT1zxsRuXxZNc/jSls8ohbg25303CmhiJR7CFeA0w8F+KNJrXO6zfsQdatPujDhk PkBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951954; x=1774556754; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=i9rYNHxfIvxcKsQ5ZLeeb8g2hhtOSjW/hV2qStJ99hI=; b=krqzIV658nlsnQ+YOYuLgg5l/Ot9jecgsIsvMan2TFO4HGhLuGnm3gWIS2wEQ5JCvT wiisYe/7i2nwt/synGhVnWwz3OxS+YRCpl7Ehn2kl77OQ+00qEKWokOHwg9YJtS1g5In OjpOnBEFVgASrfsqScsdtChNb7W3HIZXrkv1bkVwCdvkhSQ/vgbNJfJwz57NYw+T66P6 S9x5Sl7p1PQpiCiPWgv69HDNZn1F3Ex4QLk4r9UyJEOJ6YkX6SfcRCfbml2N0ElTNIMQ 6MH26vKOT74XNOqYTfx1AGacVLWT01wkqZGV7cvSQfMICxSYp8oVgjDWX4G2j15N+o62 vZZw== X-Gm-Message-State: AOJu0Yw1Ti6zUH6EjBQxpqjFxc+7urBRFSML9mKQg+mPfs+uKeiUzuEI XF5AD1B+Q3xoeQcgPlpoUffC4mP37G40PnuS1/GKgIE7cR9pZbXb4vrI3aR77PEqleY= X-Gm-Gg: ATEYQzxnvKMG/RjUtzXZGTPQenqKTohM4xR+GFr2wdX8fv5lM+QqcswXootsVyeBoRz iCyCzbsiUPMPawtTy8f1wlzBrT1rN7jRTobevgnwG1/lEAvdAgF4C2gjgasQV4X7Z+Wn7PH8bRj AmsxMFVHNZ+S5sJe5LBAj/5tTUMuCI4kJooWfDsOGP2dGhOkLwbG3zVkAUuTB6O0l70FERotQAj bFcM66oLKPMwNNygbNokBv/ktDUxTG3Ga9MnD7cs7zCPKVoiXsl6GZ5tgOyHOSh/56XfHBD1TNV c8k1SmrHY6x6E/SLkj0HviNnWgPQEQtmBdZQatXUyxxTX+O8EQ5jKRafpYteNYMM3gz6kTJOSX2 PVJ8E+9FetZCuZdOJuaimLIB9uTWTyFouIKPbtio2RUExoWrDGzwzVBDESsJHXrVQj6AJL9/8wD JqG34wXZBoj2uRjl042Z8CMnV9AJZhQ+WOcftBC/7KZabHPynX X-Received: by 2002:a05:6000:22c2:b0:43b:44e6:6e4a with SMTP id ffacd0b85a97d-43b6428ad26mr1156153f8f.52.1773951953472; Thu, 19 Mar 2026 13:25:53 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.52 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:53 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 35/55] drivers: hv: dxgkrnl: Fix synchronization locks Date: Thu, 19 Mar 2026 20:24:49 +0000 Message-ID: <20260319202509.63802-36-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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/dxgadapte= r.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; =20 adapter =3D container_of(refcount, struct dxgadapter, adapter_kref); - DXG_TRACE("%p", adapter); + DXG_TRACE("Destroying adapter: %px", adapter); kfree(adapter); } =20 @@ -270,6 +270,8 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *a= dapter, if (ret < 0) { kref_put(&device->device_kref, dxgdevice_release); device =3D NULL; + } else { + DXG_TRACE("dxgdevice created: %px", device); } } return device; @@ -413,11 +415,8 @@ void dxgdevice_destroy(struct dxgdevice *device) =20 cleanup: =20 - if (device->adapter) { + if (device->adapter) dxgprocess_adapter_remove_device(device); - kref_put(&device->adapter->adapter_kref, dxgadapter_release); - device->adapter =3D NULL; - } =20 up_write(&device->device_lock); =20 @@ -721,6 +720,8 @@ void dxgdevice_release(struct kref *refcount) struct dxgdevice *device; =20 device =3D container_of(refcount, struct dxgdevice, device_kref); + DXG_TRACE("Destroying device: %px", device); + kref_put(&device->adapter->adapter_kref, dxgadapter_release); kfree(device); } =20 @@ -999,6 +1000,9 @@ void dxgpagingqueue_destroy(struct dxgpagingqueue *pqu= eue) kfree(pqueue); } =20 +/* + * Process_adapter_mutex is held. + */ struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *pr= ocess, struct dxgadapter *adapter) { @@ -1108,7 +1112,7 @@ int dxgprocess_adapter_add_device(struct dxgprocess *= process, =20 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; =20 - /* List of opened adapters (dxgprocess_adapter) */ + /* + * List of opened adapters (dxgprocess_adapter). + * Protected by process_adapter_mutex. + */ struct list_head process_adapter_list_head; }; =20 @@ -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); =20 #define DXG_TRACE(fmt, ...) do { \ trace_printk(dev_fmt(fmt) "\n", ##__VA_ARGS__); \ + dev_dbg(DXGDEV, "%s: " fmt, __func__, ##__VA_ARGS__); \ } while (0) =20 #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 =3D host_vgpu_luid; kref_init(&adapter->adapter_kref); init_rwsem(&adapter->core_lock); + mutex_init(&adapter->device_creation_lock); =20 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); =20 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/dxgproces= s.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 *proce= ss, hmgrtable_unlock(&process->local_handle_table, DXGLOCK_EXCL); =20 if (adapter) { + mutex_lock(&adapter->device_creation_lock); + dxgglobal_acquire_process_adapter_lock(); adapter_info =3D 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 =3D -EINVAL; - } + dxgglobal_release_process_adapter_lock(); + mutex_unlock(&adapter->device_creation_lock); } else { DXG_ERR("Adapter not found %x", handle.v); ret =3D -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 *proces= s, struct dxgresource *resource) { int ret =3D 0; - int i; + int i =3D 0; + int k; + struct dxgkvmb_command_allocinfo_return *host_alloc; =20 + /* + * 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 =3D res->resource; + for (i =3D 0; i < args->alloc_count; i++) { + host_alloc =3D &res->allocation_info[i]; + dxgalloc[i]->alloc_handle =3D 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 =3D hmgrtable_assign_handle(&process->handle_table, resource, @@ -1583,14 +1602,12 @@ process_allocation_handles(struct dxgprocess *proce= ss, if (ret < 0) { DXG_ERR("failed to assign resource handle %x", res->resource.v); + goto cleanup; } else { - resource->handle =3D res->resource; resource->handle_valid =3D 1; } } for (i =3D 0; i < args->alloc_count; i++) { - struct dxgkvmb_command_allocinfo_return *host_alloc; - host_alloc =3D &res->allocation_info[i]; ret =3D hmgrtable_assign_handle(&process->handle_table, dxgalloc[i], @@ -1602,9 +1619,26 @@ process_allocation_handles(struct dxgprocess *proces= s, args->alloc_count, i); break; } - dxgalloc[i]->alloc_handle =3D host_alloc->allocation; dxgalloc[i]->handle_valid =3D 1; } + if (ret < 0) { + if (args->flags.create_resource) { + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGRESOURCE, + res->resource); + resource->handle_valid =3D 0; + } + for (k =3D 0; k < i; k++) { + host_alloc =3D &res->allocation_info[i]; + hmgrtable_free_handle(&process->handle_table, + HMGRENTRY_TYPE_DXGALLOCATION, + host_alloc->allocation); + dxgalloc[i]->handle_valid =3D 0; + } + } + +cleanup: + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); =20 if (ret) @@ -1705,18 +1739,17 @@ create_local_allocations(struct dxgprocess *process, } } =20 - ret =3D process_allocation_handles(process, device, args, result, - dxgalloc, resource); - if (ret < 0) - goto cleanup; - ret =3D copy_to_user(&input_args->global_share, &args->global_share, sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to copy global share"); ret =3D -EFAULT; + goto cleanup; } =20 + ret =3D process_allocation_handles(process, device, args, result, + dxgalloc, resource); + cleanup: =20 if (ret < 0) { @@ -3576,22 +3609,6 @@ int dxgvmb_send_create_hwqueue(struct dxgprocess *pr= ocess, goto cleanup; } =20 - ret =3D hmgrtable_assign_handle_safe(&process->handle_table, hwqueue, - HMGRENTRY_TYPE_DXGHWQUEUE, - command->hwqueue); - if (ret < 0) - goto cleanup; - - ret =3D hmgrtable_assign_handle_safe(&process->handle_table, - NULL, - HMGRENTRY_TYPE_MONITOREDFENCE, - command->hwqueue_progress_fence); - if (ret < 0) - goto cleanup; - - hwqueue->handle =3D command->hwqueue; - hwqueue->progress_fence_sync_object =3D command->hwqueue_progress_fence; - hwqueue->progress_fence_mapped_address =3D 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 *pr= ocess, } } =20 + ret =3D 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 =3D command->hwqueue_progress_fence; + hwqueue->handle =3D command->hwqueue; + + ret =3D hmgrtable_assign_handle_safe(&process->handle_table, hwqueue, + HMGRENTRY_TYPE_DXGHWQUEUE, + command->hwqueue); + if (ret < 0) + hwqueue->handle.v =3D 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 =3D NULL; struct d3dkmthandle host_device_handle =3D {}; bool adapter_locked =3D false; + bool device_creation_locked =3D false; =20 ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { @@ -651,6 +652,9 @@ dxgkio_create_device(struct dxgprocess *process, void *= __user inargs) goto cleanup; } =20 + mutex_lock(&adapter->device_creation_lock); + device_creation_locked =3D true; + device =3D dxgdevice_create(adapter, process); if (device =3D=3D NULL) { ret =3D -ENOMEM; @@ -699,6 +703,9 @@ dxgkio_create_device(struct dxgprocess *process, void *= __user inargs) if (adapter_locked) dxgadapter_release_lock_shared(adapter); =20 + if (device_creation_locked) + mutex_unlock(&adapter->device_creation_lock); + if (adapter) kref_put(&adapter->adapter_kref, dxgadapter_release); =20 @@ -803,22 +810,21 @@ dxgkio_create_context_virtual(struct dxgprocess *proc= ess, void *__user inargs) host_context_handle =3D dxgvmb_send_create_context(adapter, process, &args); if (host_context_handle.v) { - hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); - ret =3D hmgrtable_assign_handle(&process->handle_table, context, - HMGRENTRY_TYPE_DXGCONTEXT, - host_context_handle); - if (ret >=3D 0) - context->handle =3D host_context_handle; - hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); - if (ret < 0) - goto cleanup; ret =3D copy_to_user(&((struct d3dkmt_createcontextvirtual *) inargs)->context, &host_context_handle, sizeof(struct d3dkmthandle)); if (ret) { DXG_ERR("failed to copy context handle"); ret =3D -EFAULT; + goto cleanup; } + hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); + ret =3D hmgrtable_assign_handle(&process->handle_table, context, + HMGRENTRY_TYPE_DXGCONTEXT, + host_context_handle); + if (ret >=3D 0) + context->handle =3D host_context_handle; + hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL); } else { DXG_ERR("invalid host handle"); ret =3D -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) */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2CA4E3FE375 for ; Thu, 19 Mar 2026 20:25:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951961; cv=none; b=bmIlj/ZtvyhgKujcL13yuOMupwdwWLXCciZqJ6MHAk8bhmvb5YGO1yBuIHXRQdP3VkMExPvkohbJfjK+KUAIQrQkkJgddaybroUi8GutDCJWt7+X7GXkRR2HGZgbKHvez0RNN/YojhqqDwjZ1i8tH81YKfTpBDWS6IY8jkfcfO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951961; c=relaxed/simple; bh=B3ORidiU2v9AzqT4cH2PTBIt+A1SulhfgRZFmSe97F4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZPsZ09vX8LCcw7WDZQKPS7SdEjfplz6enNU9PuuMdqWxjR+PQW7LnmqY7QvGJ2RwmNOSKQvWrkflWT4xc9vtbD2Rg1PVrJhfusQJomFDl5cmoFkePB/naxE31n/YktKKfYN5nUsPTL3FXBzCYOb9+e9Cv/TKRfHx0JtZ2081qFY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fH+DWh/D; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fH+DWh/D" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-4327790c4e9so776624f8f.2 for ; Thu, 19 Mar 2026 13:25:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951954; x=1774556754; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=PMNmHW+JNOctOziyTOkJlkQy7QxdzykzDBZ9+fN3rRY=; b=fH+DWh/DBuMLkSoiDiviPi0McnmyMgpFDF3r3IrBisy8fqn7EELbcInqgOD/Uy/4qp HeM05e5VzMuArZAGqZtiO5QRRFX2fGz+bUz2MnNYC+0ceSdGWpqfcSxiA/zC9Y1qn0jO kSUQzp6DLtbeIySXSWEhYPvtTJSmvxpwI49zD9U5+tIc9Q0oSdA0z5bHSfkLw1gPk/Vq +OVzkjD2srYHPEAuK7ZyPtHGv6dTyG97op7WMccDh6cPyTjH/ULdMbz5/EVxT7d7+5gz 8a7B+6Iek/GDMu40aWE4tkObcNEWGdxBWqZpaZk56POzTP4pSIXZwf+HW30g+jLSsVMN XNRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951954; x=1774556754; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=PMNmHW+JNOctOziyTOkJlkQy7QxdzykzDBZ9+fN3rRY=; b=WMfx/zuNbldedx9rI4mXDfntFYHBTE4xr3MJ2KksReHtoGAqsF5e3G6XbeQWJKD7fY iCdejtc2rTKPXw8qw3lc2zCxkkGqsH9QFjExUiVwA4XALG8uFR8N+XDBIGDIlVQIwn3C teBNamt7asDGVnlPLKOGJ4o2PvcZUm2ePYxEipdzvVe/fpl57qfVLNrw52iSRNoNDLQ2 GiBL1ua/KByk36byoYp8i9l/6DSpYYvu1iEv1D2BR/zqJFIMgwA0a4WBaeAVGUP0cUJ4 +2vqY6+Dh2BBY1dU7271+V+pU/R3861j8mY7NW93pq3vaAvrKcxDD1Hh5LCzBEGf5dKm 0mqg== X-Gm-Message-State: AOJu0Yzf7nTrS2/ZWNnb7mBh8Kkw0dZ8NgJf/9Tg6QOJkdnghmyiG0WT HloZwwuklFQJ7xPlsn0tLJsq0mKN67w5KP3ztkCgsRQ6XoqFn/dHWD69 X-Gm-Gg: ATEYQzwZBcY0PlNNZuZbMXAc7ABTJWMZN9xnYwUDe2PXbwTCXbseboACFg+0glXDQQB Xk8+NuFgjvYaa5pgTGKGjxrE/z941QLMEFCgX6aMVMYRMGTKlBc+ep2ehGzOri3Y3xc0lggiYiB pV7xF2MFP1gknD8phb/kVHLyixkM8uvNb2iYvfCVUloGR51nN4HwP73hnxaOxr2enfLvNdanbrx cPzepv4mnpqdzYoFmRCxUGViRoJeFGXMh48TK58ZubDhtNw8iWMQRx9NqNdWQaA0ZMpntcEjJM3 eY92tqh/vyT6hcoISFT32C3J+WUD79Rph4Ie/ndnDHyMZXcG96v8iSgubrnJCDuUrYgt08H6uOw r8GgRNBDYC8ptDoORZtdWhpIA+r/kAesr3xRCn3K0/Pkz6g/SMP0aXvOAzqKBIL4z7P2w551RJF 0tTm/aZ/fHtzDg+RnQbIhjyZjkXojF7Ko4T+aPAfr2LlMdZTad X-Received: by 2002:a05:6000:18a6:b0:439:beee:43b5 with SMTP id ffacd0b85a97d-43b6423d90bmr1327203f8f.3.1773951954471; Thu, 19 Mar 2026 13:25:54 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.53 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:54 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 36/55] drivers: hv: dxgkrnl: Close shared file objects in case of a failure Date: Thu, 19 Mar 2026 20:24:50 +0000 Message-ID: <20260319202509.63802-37-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 { }; =20 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 t= ype, return -ENOTRECOVERABLE; } =20 - fd_install(fd, file); *fdout =3D fd; + *filp =3D file; return 0; } =20 @@ -4581,6 +4581,7 @@ dxgkio_share_objects(struct dxgprocess *process, void= *__user inargs) struct dxgsharedresource *shared_resource =3D NULL; struct d3dkmthandle *handles =3D NULL; int object_fd =3D -1; + struct file *filp =3D NULL; void *obj =3D 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 =3D 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 =3D 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, vo= id *__user inargs) if (ret) { DXG_ERR("failed to copy shared handle"); ret =3D -EFAULT; + goto cleanup; } =20 + fd_install(object_fd, filp); + cleanup: if (ret < 0) { + if (filp) + fput(filp); if (object_fd >=3D 0) put_unused_fd(object_fd); } From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C3563FA5E0 for ; Thu, 19 Mar 2026 20:25:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951961; cv=none; b=ehy3Ri82as0mv4f3NihBVyv9QL6BDmrbrBLcQQgVWKnNZlq8ijTg0blNHjXg4Eo8YrKN3V9CqFAWYhYZNVTnfa9aPT8ajgC0YX28NnCd3leH8k8GE1Jcg8OAHv0iQzoPejrw68wJBJoKz1iUDhXvxmplL6TdOm9WUEOcD1u9KLY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951961; c=relaxed/simple; bh=TZYhOsCGtU9mKXmRW4NBGD3j+TN7qU+aGKFvmIk5bt0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bE6FtHFnALeDtwQ+2nEJi6sY7eUf2Rizz9oWdVBpsIEhywWLPE2M5ODSJvkENEPtCDYWkO7BGm6xWFC039C5CLLNUUlvn0hMnGzK8HBs2ZtcG51NgLYN9IqqSrhPbrSsYYj302sMjqOyDN6R5nCJG4nS1Fslm2lO5Gw7r50Wzx4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=es17dUGs; arc=none smtp.client-ip=209.85.221.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="es17dUGs" Received: by mail-wr1-f44.google.com with SMTP id ffacd0b85a97d-439fe4985efso1037976f8f.3 for ; Thu, 19 Mar 2026 13:25:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951956; x=1774556756; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=hZ5+je+LO/LQ72HVOLcGhJe+wJgOlQLSoEPyelVdyag=; b=es17dUGsO8oBhP+TZQemsAsscu0nQSy5Y460KaXUA/GSmHd6AmXumeApSH+LJ5v1gb cnbDbNnGWhpct/Ig37SrWfzdJFR4wEo1VQOAd+x0y8pBiGVPBhon5Ub15xtXGmiXsNW2 TWXegD76WsxLvChyyo5Bnb2tdZPEruliCbLeWlpWu7B4TuItou56sptyWgeu62gkPDBR UHi5CYuTfh1VRyUZIwotZ9Aiyp+q1hC/siXqVVw417Pzpd58JBiTTfdI1XMZj1711upd E8ETzAY1+4d7v+qDNqP2zYNZ5o1ub0b884nZ2k1+8xX7SwhXj8nG2b+j06p0KSkb2rO7 Qf+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951956; x=1774556756; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=hZ5+je+LO/LQ72HVOLcGhJe+wJgOlQLSoEPyelVdyag=; b=XhTyYRpp4cjtEa9AMdCqnpSv1XN0ffK5gQOV/uRcq5lHivWFIDVoSQ41qNPiBM1p02 S0/HK0zny8juli850iBP/SGYeNQ815mkBIHBTiDmoMptyiaVAfZ/OrLxXpDRfMHLd76b GJiX302axwsSIaTO5oOv1RxKCOUC+UJM2+MxRxxnd4mhRea2SiRbFXZDh3R1vo53ge+U 1OQBfhyAccHR2cvbcW+vNaJSscLTc1/8jBZk9zXTAUQP1m9hzTs9xPi/SbznuX6Q838I aN1WXtqzaiWcV9W8EUQo+sxIuRyV5McPXRp7tvFgB+GEpKJ0y4b2HFXiKn0aPIBCTGAS 3MFw== X-Gm-Message-State: AOJu0YzyMaOAJrzRL+OY8UfEElQW1gTghJAXEODTBX3QHVSKaIG07cEZ 6VFWATwu6rLcCWIxVpLk5+Zxxn93LIDV4Rx7gBblk8vquVDWS0u2nK7V X-Gm-Gg: ATEYQzzLjUUe92dtN35vcE76rUCXcTb0s8eYy3eBcqmssmYXpP68Q353byj50wUu7fk gJ1YsiLzxmhQKmAqOpGzn6qiO9qoVbX/Tm6yGYcwBtD3fO00RL+lOrp1OoPXWfkks73WKG1ZP2K aDFo9ugxzL0KEd+lrevwGuF4hS1StRlJLeNGCczQLWbeMx0b3Q6vwkJF0zS+1ii8dXf97P/0KQ3 tS58Iurk3zU2t/pdTqDeqQrx3hH6GOignP79lP7f9FJaFhg/sPSN1YVx9m7fZEByacbDtSiOqIg ANtBPNEo3JXT0xUIbW6/EBSUseUuoyMi3sHztyQEYQ2Z69aCW7YPIC1XRnZOvzdBQa3KcLsn2a8 ec6ZBKrstDzu+kJv7KIaLAIgCMyQfo9+vWCLcwMyr0XqThlUQRtTnJsGDO2As2pPaJ12kRGjIPk GaotaOSlikzFCuXPxcUDB4Hb3DvInv0jaV/0zaWW5/3sxAvMR2 X-Received: by 2002:a05:6000:2dc2:b0:43b:5094:a9bf with SMTP id ffacd0b85a97d-43b64263f98mr1152697f8f.29.1773951955459; Thu, 19 Mar 2026 13:25:55 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.54 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:55 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 37/55] drivers: hv: dxgkrnl: Added missed NULL check for resource object Date: Thu, 19 Mar 2026 20:24:51 +0000 Message-ID: <20260319202509.63802-38-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 !=3D NULL) + kref_get(&resource->resource_kref); dxgprocess_ht_lock_shared_up(process); =20 if (resource =3D=3D NULL || resource->device !=3D device) { @@ -1693,10 +1694,8 @@ dxgkio_create_allocation(struct dxgprocess *process,= void *__user inargs) &standard_alloc); cleanup: =20 - 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 =3D 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); =20 + 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); From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 690E63FEB01 for ; Thu, 19 Mar 2026 20:25:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951962; cv=none; b=ZneTbZPRFpYlxFj8BiRMCrcQutkw24xNbmqeR/LBCv2DO4A6LvnmXfXg5SUY+sPQSpDGbVWo5jRJCZOXJIXD8b3UiXiDj290UFi0J93Mi/0XA3gClZ5agzkoyGBZvrjwGv5+MDDq3/J5Q9JGSQOh0Fy11BMBDtr/BhznV6avkrg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951962; c=relaxed/simple; bh=DuJ8GPWtRYe59JyQ0xpsGX/NM7LsTLaRAKg6Jd0tfj4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g2Hn5vQw9OfeiztzG3fiy1ZL5oDU87Y+4E6uJ5RuvthWL7+Mbf6bOLqRykUVdYRTUJbHQM6FSZegP93d9mepaTaKqdsVY9pai+Wc13giPQC1OOMt6/jE/V5QI/wTquIiioc4uJHnQW+ntKelWRszCFn4Kre9zba5OKXKEfHAObI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=eOjZCh+2; arc=none smtp.client-ip=209.85.221.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eOjZCh+2" Received: by mail-wr1-f50.google.com with SMTP id ffacd0b85a97d-439bcec8613so990871f8f.3 for ; Thu, 19 Mar 2026 13:25:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951957; x=1774556757; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Y5xlpp3seHS2jHJVmRJ+q5QD0+MRQpYSw44Wf7oGTOI=; b=eOjZCh+2K+msWjeGh2booTgTbAHpUkkfPbRIy81aoWIWDkcjzFhDzkhFfQOY26nckt XQxiwSRYfcOyus2c5/8uVxCQWgX69MJCr1GVXWU4gjJZMDHt+UqD4vNCgllyp8GmPlAX cI6i07L/okZky9hpemkoc3whHNw2T8eCMw2P2hxVaA6j+3wphKVTVJlFLoDBrioWP3MG blXrUA7A0HKul6NPYHLlBLKbgQqJYYgghhjunA3jZ4jL9LM2M+06suHGQLe3x61r8GY7 pMknyYSD8Uc/UhrFr9Mhs9KU49S054++ozRnGkLdVewYCjN37RF7+ArNo9NwRifnfuK5 4yBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951957; x=1774556757; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Y5xlpp3seHS2jHJVmRJ+q5QD0+MRQpYSw44Wf7oGTOI=; b=prUZWEsmio5a5mOsvRHRb4Cnh6uhNju67zX8pYgjE24eNJS93CTLUzVn+Pr7bt0BWT +WhavRUE/urruGnhMs8xIpTqoht7zNGhoLgyIeAK7hKiRY+cWqe/XJavWTNUts/C9/Tc i4dJetmoVBP7A/MUh/mQ1xHSz1oCdZAjWbzrv+fFCH3q8Fkq5k4AXre6xQicBqtE5Tyo HpF//SZNMdZBZpKnx0w2TUt1cnchbQHc7bSpiI8/1wMtpC3cYkcj9QPL/Ndif7LYyghu nWxzZofqvWRd7q/+gLHzpNIZ4+EcGHQV39yAb8imWFdoGlwktYglw/VzSaf4gPcOI0W9 P+1w== X-Gm-Message-State: AOJu0YzAdwwqNPoUmg2AsrEYscZ7/2mAvxp8fzYUTVVuG9l+TnKz+grw zqvAHUL0Bds847/O6vs3oZhUK0uVlUjOkhuGuseP9IWRLkn+MymUeXwrhgKXzXcHmuk= X-Gm-Gg: ATEYQzwFCiHD9oeaHQdXrBi8XTj5pvcr3ZHpVyNesVHLy+beEQcFog+DfI9aN83faJZ jYdbX8goXkaY8Y0tCiX2BUE4/notS8IAXqzAT+bGUV2eR8CHj9w+mekWVzThYT9eyXnHLvVZ2Nw hdJ/XSC3vWQsQozMhkNPiDoJ0bi6HtyVMbgdstSXxBgaEEEpzitrvhJASXLhoH7hYbydbME1izl mtHxmNO9C8DgirkodmFTKqmCrMcEQNKIWFwjpvsFyMGDUhW/ERpITEZr+h0ZNgAyBKM37xZRp+u m6djLSNGiFL68oN+S5wk/nLwO6VkD98maoJdjuV8gzXXQCBfLSaeYSjsKANktB96wAuR9Fuin2F CAoktwRLfbYwYosCTmAkHwefTPsTt8qmAVyCL+k+kpmRt1Iql38MwhOCCEFSFUIExVxDMZLOFFS +YsT+QlETHPAEkkzx/YFbvpbhGI+5wXC8MJInO1CMEipgGN9+7 X-Received: by 2002:a05:6000:26c4:b0:43b:4ef0:e13 with SMTP id ffacd0b85a97d-43b6424e18emr1338932f8f.12.1773951956581; Thu, 19 Mar 2026 13:25:56 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.55 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:56 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 38/55] drivers: hv: dxgkrnl: Fixed dxgkrnl to build for the 6.1 kernel Date: Thu, 19 Mar 2026 20:24:52 +0000 Message-ID: <20260319202509.63802-39-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Definition for GPADL was changed from u32 to struct vmbus_gpadl. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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/dxgadapte= r.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 *allo= c) 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 =3D 0; } -#else - if (alloc->gpadl) { - DXG_TRACE("Teardown gpadl %d", alloc->gpadl); - vmbus_teardown_gpadl(dxgglobal_get_vmbus(), alloc->gpadl); - alloc->gpadl =3D 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 =3D -ENOMEM; goto cleanup; } -#ifdef _MAIN_KERNEL_ DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle); -#else - DXG_TRACE("New gpadl %d", dxgalloc->gpadl); -#endif =20 command_vgpu_to_host_init2(&set_store_command->hdr, DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE, device->process->host_handle); set_store_command->device =3D device->handle; set_store_command->allocation =3D host_alloc->allocation; -#ifdef _MAIN_KERNEL_ set_store_command->gpadl =3D dxgalloc->gpadl.gpadl_handle; -#else - set_store_command->gpadl =3D dxgalloc->gpadl; -#endif ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); if (ret < 0) From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 757193FEB1A for ; Thu, 19 Mar 2026 20:25:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951966; cv=none; b=IVC7upwUWMf/NQtoCBVyEYLsJXcJjEnk+IwG4UZoais4SoqQrOFbrZXZjTxywO0TZFLLyzOxcxgTJfR6ywGt3M/mns5jT5ZpJrWBBo4qk0zMhGrUKfDDK/St6svve8F9gfwisOs86FHAoWMWJAcYcFdeI2INQCZu3dY+2SuVWwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951966; c=relaxed/simple; bh=YAI3oxAVt3oTr3r4AmayAs+BzXpkJkmninzM6NStvCg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iSPewcyhlSYblj2OQDvkru+t9V7RWe0PZ3d1S42G+XR9DP4e3W0mmy7wwFwUyeYfBbRB6rwhNYxpA3DGFyF3ASou8elb0l/gdHGLRv9JuiZH3swEUm87H5Vtl6OtCmMizlKBnXWjVHn46GA5XZwPen+7ZCX331MX4BFDqPooelw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=dj4x5gkF; arc=none smtp.client-ip=209.85.221.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="dj4x5gkF" Received: by mail-wr1-f44.google.com with SMTP id ffacd0b85a97d-43b527ac5d0so668831f8f.2 for ; Thu, 19 Mar 2026 13:25:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951958; x=1774556758; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yOG7RwxCRsOgk4hVW4tWFSrS7iXDUAIOM5CTFXqelFw=; b=dj4x5gkFMBLraEybzDmGsG5oR6bWFn7VzpOG4sHsA+HoRTco6dmxL5wg8jvRSquV46 cfOtLb3D5dnNdrfPdoSHK94tyfQHA/WKXFAIGc8kvEdpzYLMTjE/qhbUtO8k1esDj5j+ OZGT1XXuGoyscQ/AtjVds9gqPWnTG5Ph01GNvgAd+zJMRqquy6212t6PVTOEoLdwHS3U r5ktqKCYtA12dAO1Q1xU2HQcy/J9vyfL3mp2eyY9YkcB5BD12Ed8tNzd21BVoKFqaSJm nq0/mktlAgcVW9NNv5YHHV/agsW+QBrWApE01BylH+QyMm9B8S0S/f7YWABYHRC3UzjD BBdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951958; x=1774556758; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=yOG7RwxCRsOgk4hVW4tWFSrS7iXDUAIOM5CTFXqelFw=; b=qiTdVTkLCO5/LTNnMp2KzK+YmuQgxcSHnKEZkPD6M+M8shFxUZywKWqlhTnUK8t4V8 nHf7taPWLkRzncwjSRZsHWF9y+zy61R1QGOc5uTqrBPb9f4wwpc3HrpBaMTTFh5XvzT8 2d8DT6i73p2TCRFzOU0JT4iwlbg1Wl59c+d5KhobW/RU9uE2Eb6FTfBGBQAgPczatCdY 8a5HnRepF8U2dKs1CHhOapZOs6sPPfwJXIIjBKWHhin6sIylp8H5IFTAzk3E4yQbb2rC KmBsouTILoOPF8fENMdI7xCG83G6HCp7mG7+KOpUDGtfD6W1cZ6Epd/0jpZazTRvEjZu M25A== X-Gm-Message-State: AOJu0YwLNnrksJIRKDcW/K5smAJd8Jt1e5r8T4v/PgBxRJ3OZNOOsosn rAy3k/FgTnIppaRmPs0l4GlXu5cBDg/0OtN+JDQRoYTXyNczgxH6XrOB X-Gm-Gg: ATEYQzw/aDhDlFX64jpj+QQPq//gDylNFJjvAGK1lO/XfSoNwQnZvCUrFvQRiw0TNOA Q27Uzixq7kLErmf25iOmZpL+kvTXjIv3Q1mPnORwN1niRPouewtplTzqj8vSzU9ScYcaWlGuHJj Wme3dzZhd7d/9ICiqXI0itcG71PLX/SR4TxwSQovdflPBZ7XQYEonTkr6dyXiseXd2nFNNFae55 3nmUq8pWSEaFVZLRea8dpqcGwr7Dm6iZ265oO9Ij2YUKoJAoAyIfb1gdA6CS04XmQ1ilwPq9Hgl 7+HFRahFCTRTwqYok4quD4EL4EahQofe8u7D8X7sM+25+Gr0LAEo1lyJNHJILLYTjqA4Vs3Y1HX ADD0osZNgB4J6uxUA6+qO66Uaj3YLRb3uw4CRy5AsQLfC1iwwBXqeX1r/ePeT4u8CHeeXp/Epzh 7wto+3mKtEmK0QwD/ZMi7PARv0z3kYNpACR/Jt19XDde+n1UGb X-Received: by 2002:a5d:588f:0:b0:439:b3a3:7239 with SMTP id ffacd0b85a97d-43b6423fb3dmr1307686f8f.5.1773951957610; Thu, 19 Mar 2026 13:25:57 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.56 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:57 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 39/55] drivers: hv: dxgkrnl: Added support for compute only adapters Date: Thu, 19 Mar 2026 20:24:53 +0000 Message-ID: <20260319202509.63802-40-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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; }; =20 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 @@ =20 #define PCI_VENDOR_ID_MICROSOFT 0x1414 #define PCI_DEVICE_ID_VIRTUAL_RENDER 0x008E +#define PCI_DEVICE_ID_COMPUTE_ACCELERATOR 0x008A =20 #undef pr_fmt #define pr_fmt(fmt) "dxgk: " fmt @@ -270,6 +271,8 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_= t *guid, =20 adapter->adapter_state =3D DXGADAPTER_STATE_WAITING_VMBUS; adapter->host_vgpu_luid =3D host_vgpu_luid; + if (dev->device =3D=3D PCI_DEVICE_ID_COMPUTE_ACCELERATOR) + adapter->compute_only =3D 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[] =3D { .subvendor =3D PCI_ANY_ID, .subdevice =3D PCI_ANY_ID }, + { + .vendor =3D PCI_VENDOR_ID_MICROSOFT, + .device =3D PCI_DEVICE_ID_COMPUTE_ACCELERATOR, + .subvendor =3D PCI_ANY_ID, + .subdevice =3D PCI_ANY_ID + }, { 0 } }; =20 @@ -962,4 +971,4 @@ module_exit(dxg_drv_exit); =20 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 =3D 0; adapter_type->acg_supported =3D 0; adapter_type->support_set_timings_from_vidpn =3D 0; + adapter_type->compute_only =3D !!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, =20 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) =3D=3D 0) { struct d3dkmt_adapterinfo *inf =3D &info[adapter_count]; =20 @@ -474,6 +476,8 @@ dxgkio_enum_adapters(struct dxgprocess *process, void *= __user inargs) =20 list_for_each_entry(entry, &dxgglobal->adapter_list_head, adapter_list_entry) { + if (entry->compute_only) + continue; if (dxgadapter_acquire_lock_shared(entry) =3D=3D 0) { struct d3dkmt_adapterinfo *inf =3D &info[adapter_count]; From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A957E3F99D4 for ; Thu, 19 Mar 2026 20:26:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951966; cv=none; b=f1XJNmqTguY9F8FWv8KpjDMuZANf0KperqZp9iogvxkUQea9DMIjjC3Jrsf17UAFzMzCntCmf9ao1D6bHKg2lm9jz7LD8z6dG5WEd9GBNpZxQCs+PM43rrBF79AGuc1GQJlX+hyAxivHVwADll1fz+klWkQK+0x49a7QAgncZUA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951966; c=relaxed/simple; bh=nGQEUYXMbIpENLhAOSk8xQWfjI3kmrYM3QvmNVStmhg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SauOQEBrWMQVGvFx1w2DE5gnwBmcKWKWwPGVUiNovAGtg/dbPqbvTIq65p9tyn/kLwa0uuSgRqpy9+NISW+a7bOkTHmwdqvPvEisI3tAceY93jNKoyW6HZ3OpBOrrXj0rBI+SxlG5DEA94Htj0vSBBQggx/k3R/K/L7TCT9ZlQ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=H7ACAmSK; arc=none smtp.client-ip=209.85.128.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="H7ACAmSK" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-4852b81c73aso12627105e9.3 for ; Thu, 19 Mar 2026 13:26:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951959; x=1774556759; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=SjOW9NEQVjgaApfYoWy4DLUz7WyMSSyTvWEPSEVJm70=; b=H7ACAmSKstFHJYV+ediGGpf6r7+EVQTrlLBnQOvNrSy5FJG8uFzrBoaxwocmg3mWq3 +fydPRz4GXaQXCnVZAyWKjHH93JC0TvKRBq5m75B1t6WjgcieNO/0aNBzbtbuycI2bnr X3u85blQ7HbymCggcWGwxUD9kwuVNslcb5IYpoI7830wdQIcfKDpFXSCMPU4ZXhsryTM 3DbnovfyC8QkNqLutwRfykmJT23QXFxvRGEpuXGpkpxYix/VTxa5vehOus8S2Pu1Zaop R6nybt3EFiMSjUom/zX2BfSCQy9NWmMVucr7ilU4OCXGCPFh5nqdds3HMAr7jNredX1i dWRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951959; x=1774556759; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=SjOW9NEQVjgaApfYoWy4DLUz7WyMSSyTvWEPSEVJm70=; b=U2qgY5n+GjOpYbK7kmKKhIMjJwkdH7pttQEsFgBYVXS3ODuYm3F/AvljEo+8+JM9eY d/7YOdhO71NQQHMFW0gXXQTQVxNBt+SbjJIQcn40BYoPwZdmV9TgjjBhZc+MdBuY/Fuh nVdnx6HJVqzE6eiNuep4mjkZwWMoIe3pvrA2ni0S46svbMEjZ5KpIDbpNBpcF0Xj9ZZr Q0sZ+Us5UM6yCEgHaixVy+NoyWUD+odHOToGSN4qfvWwVHTPe0ujjtqYMDcLojdeKz0j LdSUnCLs5E1dqIrs49QZYA3v4x/b3OjC/mwAJ47C3IvXqtq6di1uI3/T9+9JN1T9GY4I f/9Q== X-Gm-Message-State: AOJu0Yy7G+zsBkbfOMQVH5RHUq9PnHH4f/v6iQUVu4gYrK5edlkQsPxn KQ2zkol6J4jBJ2M/4SHyLPQOWQCA4C1dCxtakUGEmnbjaBtnfgRWp9pb X-Gm-Gg: ATEYQzxH51NwimEL2lDsX0qvnRprMq7wzUPiG5iCx6LPDzFhofPx2ENYu+/NUeu9Ya9 lxF20w0zZYaOYXbKXz6Hhdj/K5CHHZRBOzEdry3gX+E27/ndQsuI8EEllVxyNM5aCLT3ux6LYJ0 7I1F9IUlOFgKbZUdgllB+Sc0+u7OLCNxMsYk/0Py0d7jmAHUsuhCkY9uJQEFjjDakzPwS6jBSY+ GD1OcfgRcOm7wcf4zXfZtkflA5tSRmGJ7RlT2D1U+weZJaOQwdruRwc7X9OaIEPR0GNGVnMRCEd ZtAuhegH5tjinZ8ysyYk01ukkOt7DDvzsZIGOMk2UMl4iecXPqCvt4OoygFSJgAg8NomuX0xS0y j+spIbwSWWv53xh7tmYlyafw5/o7iFhAqMYd463HhTJaFvLCB9Y1R5oRgHkVj0nXdrtTGnSW/oR T5miabAA3FJirUTS8TpHVOSc2lBFfIZfpcHMijbWMoIVW5bAVb X-Received: by 2002:a5d:5d86:0:b0:43b:3e0b:721e with SMTP id ffacd0b85a97d-43b64281744mr1116157f8f.40.1773951958654; Thu, 19 Mar 2026 13:25:58 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.57 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:58 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 40/55] drivers: hv: dxgkrnl: Added implementation for D3DKMTInvalidateCache Date: Thu, 19 Mar 2026 20:24:54 +0000 Message-ID: <20260319202509.63802-41-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 *chann= el, 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); =20 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 dxgpro= cess *process, return ret; } =20 +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 =3D {.hdr =3D NULL}; + + ret =3D init_message(&msg, adapter, process, sizeof(*command)); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_INVALIDATECACHE, + process->host_handle); + command->device =3D args->device; + command->allocation =3D args->allocation; + command->offset =3D args->offset; + command->length =3D args->length; + ret =3D 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 =3D 64, DXGK_VMBCOMMAND_LOGEVENT =3D 65, DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES =3D 66, + DXGK_VMBCOMMAND_INVALIDATECACHE =3D 67, DXGK_VMBCOMMAND_INVALID }; =20 @@ -428,6 +429,16 @@ struct dxgkvmb_command_flushheaptransitions { struct dxgkvmb_command_vgpu_to_host hdr; }; =20 +/* 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 *pro= cess, void *__user inargs) dxgadapter_release_lock_shared(adapter); if (adapter) kref_put(&adapter->adapter_kref, dxgadapter_release); + + DXG_TRACE_IOCTL_END(ret); return ret; } =20 @@ -4333,6 +4335,49 @@ dxgkio_flush_heap_transitions(struct dxgprocess *pro= cess, 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 =3D NULL; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EFAULT; + goto cleanup; + } + + device =3D dxgprocess_device_by_handle(process, args.device); + if (device =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgdevice_acquire_lock_shared(device); + if (ret < 0) { + kref_put(&device->device_kref, dxgdevice_release); + device =3D NULL; + goto cleanup; + } + + ret =3D 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; } =20 @@ -5198,7 +5243,7 @@ static struct ioctl_desc ioctls[] =3D { /* 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[] =3D { /* 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}, }; =20 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 */ }; =20 +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 \ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 17D4B3FE37D for ; Thu, 19 Mar 2026 20:26:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951967; cv=none; b=SB+nCGUqjLZHem4IAGqaTSQ8yfwdrF9nG9RKVa7IRWQZ3liwOUYfPPhxW/kVYKtDAq39djDVuHw6z0Wdicp2ntCk+q5g3tdloUex/6jTkw5jMHF9rBqsSemX4qe59hwCpEg/e+fLvCOL/x5B87SKqXW3Sqv38GgRuKacx6/bFvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951967; c=relaxed/simple; bh=5GYgyHAPPb/c4TuOt/FovFbs4KdkJcctdoNSZgSBCI0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LN6GyKtmXxIobPufxIsUSEdhrTgiJ/LuweEvtq6+UjgUifoN2zwSoVZHpOc20iFcokMfapFZE6Ttrc+vijwfyO1W4p4wGDiJP5ABsPT35B2FatNB1XYOiZUJZqhXGssw8SHzcgIRRbzHTQ9yf9j3XIvtvXoERJItyQKT8rO8J5w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Z1omyZ3+; arc=none smtp.client-ip=209.85.221.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Z1omyZ3+" Received: by mail-wr1-f42.google.com with SMTP id ffacd0b85a97d-439b611274bso598558f8f.3 for ; Thu, 19 Mar 2026 13:26:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951960; x=1774556760; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GxByceTa1YltExdfah9Lq3qXbpogAji5TptAgxuELUc=; b=Z1omyZ3+dWSDCnB+sTdM6BZTxwibX42H8JzDqMs7LXfbqsp0B2Wu4w96T8E86UbxYN CzNEjbfUykgrrf7Uk//pw1pY6bG+m0KgBbXHCeNcsGu0RwsAtYfI+V1YVQtN4gRIB3U/ ymNWouJlWSAqsYYU3ThkecLlhZI2dI2iR94eeLpayt5U3b3d7uCf98y7wLOSbcGRRY3s SXpnt398S1qyU1WKcWGDJLMzdhm0i/hwfFgGyLJh4D2aXa21brzrIH2dTfJpYiqg8A+P SPEORwPG4/970YzcPgMpynSMAJ5bNiJ0WcMvl+N46iqHTyi59TpCg11IiJDq17QXOVt4 CCig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951960; x=1774556760; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=GxByceTa1YltExdfah9Lq3qXbpogAji5TptAgxuELUc=; b=sOCgDSzNEW0QnjfoTHMmsG2DOz+25ptxl2pRaWNXC/0nFKBpmXQ0pkHyrg1FEmoCAZ vUELBKyTv5cnMegKLiGQ8kAOBWVuGcrOUCFvYXvg85gHBJKfzsMkzkGKEkUzjKks6N6o 6Smx4bBKAf/qEoHHS075KpuxDl+GRtkvdoB5lmqT+gpD4tE1jBaZ86MiFKKkfm/r/HgM kZAAq2I0jypetqmyl/wKnJLW0j5dISqWI0Asfu70fv+lip7XV2UwpEazVrxG2VQXOC+i AUKnoOllttedi49QK0cxHwqcpRc8Dsc1drcWBDGB2e336rQ2fzk7CD8sPiYn/fb8p6jV clsA== X-Gm-Message-State: AOJu0YwiL9fpMLDWAgmGzCt9sbwJ9hGWFvibV2gXmU0UMjKDS34zL2nl XfPEJY52pL3BRER7ZXnG9KT7y4STLsJGroMH07mKWmTtlA37g3qI80a9 X-Gm-Gg: ATEYQzzqxdXABiWfORz0pCz7zBHBfNSS/hKa0T38aTGYntUdVj3U3+OHqQomznHBJ57 EqDocr+Gczm8jTtYTF5U2dmjrbgGCwNeElT53yu+iJpf8/yI2yK5eX/NmRKBPF0fp8ys0TMsPYy XEDFkGVcrnOwt0BDhxbHjZPzo9jv0nI1OlAPLvqJcd/i6e47CJJ3cCDqb0HkjtyBwcP7BmmbBPs avdnZiZofoCLByJQKTbRqb+aorcqZHL6a3/1h+X3HDnTYY9Cvdd2nDJ/97ioZ5pzyxnWz/5YMy3 jQO6sIRGCZVxhfEsAhTQOer69qftQit2CwgGbYnyNUILaOIxZnx+u3+uixBdRZr3QHNkAVPoDN7 Cw59aKHrAFaFHQqdQDHeFrpstkIlgKR67OJ6AsCSVau/YwndWEjl3+Ki/lwOWzJNE4pp9mJrQC/ mGd7Fk54D25PIiTo83j//1KMk3VsqdSbkiRsrOLcl2w8n6YqZV X-Received: by 2002:a05:6000:40c7:b0:439:bcc2:bf0a with SMTP id ffacd0b85a97d-43b6424f867mr1134796f8f.23.1773951959951; Thu, 19 Mar 2026 13:25:59 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.58 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:59 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 41/55] drivers: hv: dxgkrnl: Handle process ID in D3DKMTQueryStatistics Date: Thu, 19 Mar 2026 20:24:55 +0000 Message-ID: <20260319202509.63802-42-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 *dev= ice, 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/dxgproces= s.c index fd51fd968049..5a4c4cb0c2e8 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -12,6 +12,7 @@ */ =20 #include "dxgkrnl.h" +#include "linux/sched.h" =20 #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 =3D current->pid; process->tgid =3D current->tgid; + process->vpid =3D task_pid_vnr(current); ret =3D 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" =20 +#pragma GCC diagnostic ignored "-Warray-bounds" + #undef dev_fmt #define dev_fmt(fmt) "dxgk: " fmt =20 @@ -113,7 +115,6 @@ static int init_message(struct dxgvmbusmsg *msg, struct= dxgadapter *adapter, =20 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; } =20 -static void free_message(struct dxgvmbusmsg *msg, struct dxgprocess *proce= ss) +static void free_message(struct dxgvmbusmsg *msg) { if (msg->hdr && (char *)msg->hdr !=3D msg->msg_on_stack) vfree(msg->hdr); @@ -646,7 +647,7 @@ int dxgvmb_send_set_iospace_region(u64 start, u64 len) =20 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 *proce= ss) dxgglobal_release_channel_lock(); =20 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 pro= cess) dxgglobal_release_channel_lock(); =20 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, } =20 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 *pro= cess, *syncobj =3D result.sync_object; =20 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 dxgproce= ss *process, } =20 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 d3dkmth= andle shared_handle) dxgglobal_release_channel_lock(); =20 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(); =20 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 dxgproces= s *process, args->object_vail_nt_handle =3D result.vail_nt_handle; =20 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 *adapt= er) adapter->host_handle =3D result.host_adapter_handle; =20 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 *adap= ter) =20 ret =3D 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 dxga= dapter *adapter) sizeof(adapter->device_instance_id) / sizeof(u16)); dxgglobal->async_msg_enabled =3D result.async_msg_enabled !=3D 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 =3D 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 *ada= pter, =20 ret =3D 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 =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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, } =20 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 *ad= apter, =20 ret =3D 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 =3D args->paging_queue; =20 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 dxgproces= s *process, ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, NULL, 0); =20 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); } =20 - 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, =20 if (result) vfree(result); - free_message(&msg, process); + free_message(&msg); =20 if (ret) DXG_TRACE("err: %d", ret); @@ -1950,7 +1951,7 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess = *process, =20 cleanup: =20 - 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 dxgpro= cess *process, ret =3D ntstatus2int(result.status); =20 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 dxgproc= ess *process, process->host_handle); ret =3D 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 *p= rocess, command->length =3D args->length; ret =3D 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 dxgproce= ss *process, } result_size +=3D result_allocation_size; =20 - ret =3D init_message_res(&msg, adapter, process, cmd_size, result_size); + ret =3D init_message_res(&msg, adapter, cmd_size, result_size); if (ret) goto cleanup; command =3D (void *)msg.msg; @@ -2115,7 +2116,7 @@ int dxgvmb_send_query_alloc_residency(struct dxgproce= ss *process, } =20 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, } =20 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, } =20 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 *p= rocess, args->execution_state =3D result.args.execution_state; =20 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 *proc= ess, sizeof(*result); struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; =20 - ret =3D init_message_res(&msg, adapter, process, sizeof(*command), - result_size); + ret =3D init_message_res(&msg, adapter, sizeof(*command), result_size); if (ret) goto cleanup; command =3D msg.msg; @@ -2342,7 +2342,7 @@ int dxgvmb_send_open_resource(struct dxgprocess *proc= ess, alloc_handles[i] =3D handles[i]; =20 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 *d= evice, result_size +=3D *alloc_priv_driver_size; if (priv_res_data) result_size +=3D *res_priv_data_size; - ret =3D init_message_res(&msg, device->adapter, device->process, + ret =3D 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 *d= evice, =20 cleanup: =20 - 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 *proc= ess, =20 cleanup: =20 - 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, =20 cleanup: =20 - 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 *pro= cess, =20 cleanup: =20 - 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, =20 cleanup: =20 - 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 *pro= cess, args->virtual_address =3D result.virtual_address; =20 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 *proces= s, ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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 *proc= ess, ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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 *pro= cess, } =20 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, } =20 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 dxgproces= s *process, ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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 dxgproces= s *process, } =20 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); =20 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 =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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 dxgproce= ss *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 dxgproces= s *process, command->args =3D *args; ret =3D 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 dxgpro= cess *process, ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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 dxgpro= cess *process, } result_size =3D sizeof(*result) + priority_size; =20 - ret =3D init_message_res(&msg, adapter, process, cmd_size, result_size); + ret =3D init_message_res(&msg, adapter, cmd_size, result_size); if (ret) goto cleanup; command =3D (void *)msg.msg; @@ -3352,7 +3352,7 @@ int dxgvmb_send_get_allocation_priority(struct dxgpro= cess *process, } =20 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 dxgpr= ocess *process, command->in_process =3D in_process; ret =3D 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 dxgpr= ocess *process, *priority =3D 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 =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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 +=3D (args->allocation_count - 1) * sizeof(enum d3dddi_reclaim_result); =20 - ret =3D init_message_res(&msg, adapter, process, cmd_size, result_size); + ret =3D init_message_res(&msg, adapter, cmd_size, result_size); if (ret) goto cleanup; command =3D (void *)msg.msg; @@ -3537,7 +3537,7 @@ int dxgvmb_send_reclaim_allocations(struct dxgprocess= *process, } =20 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 dxgp= rocess *process, =20 ret =3D 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 *pro= cess, dxgvmb_send_destroy_hwqueue(process, adapter, command->hwqueue); } - free_message(&msg, process); + free_message(&msg); return ret; } =20 @@ -3731,7 +3731,7 @@ int dxgvmb_send_destroy_hwqueue(struct dxgprocess *pr= ocess, ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); =20 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, } =20 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 dxgpr= ocess *process, } =20 cleanup: - free_message(&msg, process); + free_message(&msg); if (ret) DXG_TRACE("err: %d", ret); return ret; } =20 -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 *p= rocess, int ret; struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; =20 - ret =3D init_message_res(&msg, adapter, process, sizeof(*command), + ret =3D init_message_res(&msg, adapter, sizeof(*command), sizeof(*result)); if (ret) goto cleanup; @@ -3897,7 +3897,7 @@ int dxgvmb_send_query_statistics(struct dxgprocess *p= rocess, =20 command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_QUERYSTATISTICS, - process->host_handle); + host_process_handle); command->args =3D *args; =20 ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, @@ -3909,7 +3909,7 @@ int dxgvmb_send_query_statistics(struct dxgprocess *p= rocess, ret =3D ntstatus2int(result->status); =20 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 dxgpro= cess *process, return ret; } =20 +static struct d3dkmthandle find_dxgprocess_handle(u64 pid) +{ + struct dxgglobal *dxgglobal =3D dxggbl(); + struct dxgprocess *entry; + struct d3dkmthandle host_handle =3D {}; + + mutex_lock(&dxgglobal->plistmutex); + list_for_each_entry(entry, &dxgglobal->plisthead, plistentry) { + if (entry->vpid =3D=3D pid) { + host_handle.v =3D 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 *p= rocess, struct dxgadapter *adapter =3D NULL; struct winluid tmp; struct dxgglobal *dxgglobal =3D dxggbl(); + struct d3dkmthandle host_process_handle =3D process->host_handle; + u64 pid; =20 args =3D vzalloc(sizeof(struct d3dkmt_querystatistics)); if (args =3D=3D NULL) { @@ -170,6 +189,18 @@ static int dxgkio_query_statistics(struct dxgprocess *= process, goto cleanup; } =20 + /* Find the host process handle when needed */ + pid =3D args->process; + if (pid) { + host_process_handle =3D find_dxgprocess_handle(pid); + if (host_process_handle.v =3D=3D 0) { + DXG_ERR("Invalid process ID is specified: %lld", pid); + ret =3D -EINVAL; + goto cleanup; + } + args->process =3D 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 *p= rocess, if (adapter) { tmp =3D args->adapter_luid; args->adapter_luid =3D adapter->host_adapter_luid; - ret =3D dxgvmb_send_query_statistics(process, adapter, args); + ret =3D dxgvmb_send_query_statistics(host_process_handle, adapter, + args); if (ret >=3D 0) { args->adapter_luid =3D tmp; ret =3D copy_to_user(inargs, args, sizeof(*args)); @@ -280,7 +312,10 @@ dxgkp_enum_adapters(struct dxgprocess *process, dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED); =20 if (adapter_count > adapter_count_max) { - ret =3D STATUS_BUFFER_TOO_SMALL; + struct ntstatus status; + + status.v =3D STATUS_BUFFER_TOO_SMALL; + ret =3D ntstatus2int(status); DXG_TRACE("Too many adapters"); ret =3D copy_to_user(adapter_count_out, &dxgglobal->num_adapters, sizeof(u32)); From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f47.google.com (mail-wm1-f47.google.com [209.85.128.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D51933FF8A6 for ; Thu, 19 Mar 2026 20:26:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951968; cv=none; b=HfTnuTM7Vz3le2k5v81sReRJAZbXx2szjct4RmKPrTVFxIgMyzOuKHma47xoE21LUlLIFCj7uoZpgpfNEJlIVxsMBOoguu8di1oO5nuZhCVrOs4p0jbs1lDPGkIn9xDbZ1nfB7EobgGjM3sTPtvXokpXiPz/l7e3y/O1+1OKvnM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951968; c=relaxed/simple; bh=9EotiCR3a/bxXyYpH48uROjU7TaRXAUW+3QQzC9Rnbc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Xc7RsYjJLO1em8TMjyOYhOJNbY02fpmz9vWnahefbok3dE5ZfeLlcwjDDBhvgx5lF0hAqB+CvzhrFt98/ecxIcauD40SEflwo8VcqyUGZMiOjmmjWq4bl8f3dXcXo+VnmdCwIsdgxx05KKBKs5aaP7y4ugu2VzuFg5++FVYRabw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=nL4NG0vh; arc=none smtp.client-ip=209.85.128.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nL4NG0vh" Received: by mail-wm1-f47.google.com with SMTP id 5b1f17b1804b1-486fb439299so9165495e9.0 for ; Thu, 19 Mar 2026 13:26:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951961; x=1774556761; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=vOXddkLS+afnHqsg7GZzmCZXh9PBt2zVroRp0TwjKzA=; b=nL4NG0vhsgX6T8bi4rvzNOeki73cfUhydz5DeZXY3Urc/SWsNzwETkpluYeut9rhRS FItW5/49a1EfED+YXcPV+9bv3xxtW99ogBvgd1f1cs3eVl2QcjgGlQK40wrjMlfO8w1X nZ6ZCz42+IMcqcP5EWmpaeRN7JhoG/dzD74/8qtQ8yBeHtBieG77qzT9Jpuul7c1D/gP vQa9GpbO6XyHK0fn3St7t4KXlZEDSRiZaCHq2ll5V8Rn15yEwMTN/KklbgG+sTFgDtPt XJTpXkW2vJAIOiZptfKzysu5MrtFApe2OmaVWW+fXCcPhJhvrRWdAWsGPoKf9cplOTNk k8zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951961; x=1774556761; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=vOXddkLS+afnHqsg7GZzmCZXh9PBt2zVroRp0TwjKzA=; b=IpqwwNkX8qNv7ZIEYNHippqIDUlAmU+GHWsv1BMSLpT+E6xTJBBcVOagBPcbnvnxVS +Ky0HnI81Wmo7QrqtxIpz/ttRI0GFzWQBC7Y6Zj1oeZm89w2vatLiSezwT4mh0q9w81W TfLOZTIHJIUcZzADvcKE+kE9KaQ6/pLL7JIoW0vmmsrKbHSo2nxPUX4sLX3xGAqNmv1t yMD9A/EWThhtcJ6z2Z1KImFDgwwebvBQOY97hHk6n3Df8HmuZm0/NxQ0RqaUSFvO5MSw /weCIDQszJXeCw2KjgI/fr3enzWcupDJeUABTB+pU+l1/7wSsIgXMPcsBGExd5QAhCVi 6EZg== X-Gm-Message-State: AOJu0YxswIcTAaqWczfA0hyTcCGU9c3EmefFhnuQQZBmAg1E83xk2W/I TxBOr+CazIK06GIE14Cd9GmDt63EACZw1xQo9ABNzmSyqty1vojUu35z X-Gm-Gg: ATEYQzyXGMcerEbXofMJXac690tQX3TIoisHVDgVUs+fhMOCzLk7pnIr9IdurIhFe8C 4xdNlRGywGEEZXnsXJQlhFTLGGBEFi7wsfyXqKrVxcDpXwuQIqmqgLGSKQ6icPZis69M1P7OCpf Z2/eVOaZZUT1k3p5HL7GjPqIABoRaaQD6gQYvns4sWk+aVJHFVjE+erVfC2nqEHhN0gT944dkXX rImaYyi2x8Jnh2yUr9rm8drLHLOhItO0cP8vhUc0c56j5ldVvppZFGslYp648yevYMhgzmFsC5e gZiD+WeM4rYNtoMjYsElbtBslZby7YPgN/u3nhd9zpRPAeJkpcrVob7vlrC4diM2nVB03BqIPX4 BtR5m/4xfYRV+HlatIzEx0GeN3Jwmk8hbDvn0Bv3q4r+E8jr6AvGvzBBembg0HE4kLdRc63o2UP W/Xxfzg8rq9bWICMYSGcyHD2Eq6NQj6+JmEYAp3yiLonTkU4k7 X-Received: by 2002:a05:600c:c48f:b0:485:2a85:e5ec with SMTP id 5b1f17b1804b1-486febb60c6mr7537765e9.2.1773951960885; Thu, 19 Mar 2026 13:26:00 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.00 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:00 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 42/55] drivers: hv: dxgkrnl: Implement the D3DKMTEnumProcesses API Date: Thu, 19 Mar 2026 20:24:56 +0000 Message-ID: <20260319202509.63802-43-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov D3DKMTEnumProcesses is used to enumerate PIDs for all processes, which opened the /dev/dxg device. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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/dxgproces= s.c index 5a4c4cb0c2e8..9bfd53df1a54 100644 --- a/drivers/hv/dxgkrnl/dxgprocess.c +++ b/drivers/hv/dxgkrnl/dxgprocess.c @@ -13,6 +13,7 @@ =20 #include "dxgkrnl.h" #include "linux/sched.h" +#include =20 #undef dev_fmt #define dev_fmt(fmt) "dxgk: " fmt @@ -33,6 +34,7 @@ struct dxgprocess *dxgprocess_create(void) process->pid =3D current->pid; process->tgid =3D current->tgid; process->vpid =3D task_pid_vnr(current); + process->nspid =3D task_active_pid_ns(current); ret =3D 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 #include #include +#include =20 #include "dxgkrnl.h" #include "dxgvmbus.h" @@ -5238,6 +5239,85 @@ dxgkio_share_object_with_host(struct dxgprocess *pro= cess, void *__user inargs) return ret; } =20 +static int +dxgkio_enum_processes(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_enumprocesses args; + struct d3dkmt_enumprocesses *__user input =3D inargs; + struct dxgadapter *adapter =3D NULL; + struct dxgadapter *entry; + struct dxgglobal *dxgglobal =3D dxggbl(); + struct dxgprocess_adapter *pentry; + int nump =3D 0; /* Current number of processes*/ + struct ntstatus status; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EFAULT; + goto cleanup; + } + + if (args.buffer_count =3D=3D 0) { + DXG_ERR("Invalid buffer count"); + ret =3D -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 =3D=3D *(u64 *) &args.adapter_luid) { + adapter =3D entry; + break; + } + } + + if (adapter =3D=3D NULL) { + DXG_ERR("Failed to find dxgadapter"); + ret =3D -EINVAL; + goto cleanup_locks; + } + + list_for_each_entry(pentry, &adapter->adapter_process_list_head, + adapter_process_list_entry) { + if (pentry->process->nspid !=3D task_active_pid_ns(current)) + continue; + if (nump =3D=3D args.buffer_count) { + status.v =3D STATUS_BUFFER_TOO_SMALL; + ret =3D ntstatus2int(status); + goto cleanup_locks; + } + ret =3D copy_to_user(&args.buffer[nump], &pentry->process->vpid, + sizeof(u32)); + if (ret) { + DXG_ERR("failed to copy data to user"); + ret =3D -EFAULT; + goto cleanup_locks; + } + nump++; + } + +cleanup_locks: + + dxgglobal_release_process_adapter_lock(); + dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED); + + if (ret =3D=3D 0) { + ret =3D 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[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -5325,6 +5405,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x46 */ {dxgkio_wait_sync_file, LX_DXWAITSYNCFILE}, /* 0x47 */ {dxgkio_open_syncobj_from_syncfile, LX_DXOPENSYNCOBJECTFROMSYNCFILE}, +/* 0x48 */ {dxgkio_enum_processes, LX_DXENUMPROCESSES}, }; =20 /* 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 */ }; =20 + 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) =20 #endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F073D3FEB17 for ; Thu, 19 Mar 2026 20:26:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951969; cv=none; b=Aj3Fo5a37exuQ8bBLA+pW7e0RVqRAnbv0K/88HAmyuYyE1yvzz1KcpMdPUMbYU7ZLWL1VZvvBUGQEu5edkiU2xclKy7knhegKShNREAbyXEemmaeNe+POHTZqWMuO81xEKGX3BpBmYG62wG0NGhUFpZ73t/9ksiCBbtgDDkHMTQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951969; c=relaxed/simple; bh=Z4PYI3Irnqgd469D+z9UfdlrSw8gbWCsjEqZiiqnGOc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=B9lSlhIvRGp5aedV8nqaqGuxs59XqjGAJKIu94MJgOrtEUFow8GZrg3hvJcwHZfsgKau99ngL3Mv5I2j9Pfiigt1FftAo3cU7HpyeBnXQnTaBRtLZ86uv3KcTOGzppCWYxKh5qMaQzcrs5oyIwN9WRgPH3COWOwWoTEI2CfZCqo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=YgPi6iKA; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YgPi6iKA" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-485392de558so9141165e9.1 for ; Thu, 19 Mar 2026 13:26:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951962; x=1774556762; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=z6+n+f//BdkXFe0SxztsrgegLDZqmvdOMqnM0EvvH8Y=; b=YgPi6iKAAyEd6ZDihlMD8u7aPvOmJpI/t/EbvwSc0/YaNsSisFnEL8ZoZt8DMRI3Xv LDhV5wvYHKfsdv+u/0CNdEL8LylPPxP7Meb/GRtMonr9XS8v7R5B+SyBLAu/P/9v0zhv zHja+uDJgWlYpTkq6ItJB/K3ky3nKLtmXzRL5Wzcuu0VaKvb2KhwPx6cqCAZ/yZJQBNE 5mrYzb0KN9EKyDHtK5Wv596Dg9SSuDHkSB4+owMt1m3kVVYxpesaEUxV7FjXBV58NYHM Gi5rTyMWMq/6ygCBNPShwbvdvIkMhLGRZaL2HdRNW+Nkk0Cd9kbUnlbAmdItjteTXTrD DW9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951962; x=1774556762; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=z6+n+f//BdkXFe0SxztsrgegLDZqmvdOMqnM0EvvH8Y=; b=fLlQ2D3YQaUOeueLyZU2LnFNNqSexmnvP2EnQhDBFTcoO7UtEGCI7AXAkd9p/8YK15 FxzJk/OXaiTBz5PX7J7F6ntj0AD2kQ1RsmOin22UajhJGuwkjKvSj3EwBw5qoVU4IBfT a3R9eDmSuzDSFe0vncmitT+z0V9SPDMuLz3ok+e5PlQJYQcB0wFkBcw8cZqmEOjqdM5v yGzGres0ixkKDk831UELr2Yye/5cmKh6SaWBFhrghUWA28ZtSZatgUaX+4WIModzpEcc qP9zaO+6IDlvzzUV0nrOjIq4sgnmK9r1yNsk6JEoLWjikiUC7hTSH5egT0GYj2tismh0 H57w== X-Gm-Message-State: AOJu0YzQxyf/OwS0ZruvQtBA9KltVTwTdXmH+GNAAmrA45/ZN9of2Npr wQgFMKHmcU06XulBI8UiqgeieAUfWT3idQoJBK3aZkVgwYWSBS5WaspsyFpa62HT8Og= X-Gm-Gg: ATEYQzx3ooqw0H8PacMxazHcVKzlmxW09m402/BLU7vDICF/SOt4rbrxYsKX9E72jNM ZksxS1YVtfVFtmkrV7lSUDSFIxKCW2l8UbgO6Ya3nBUZ/vVz4lNGFoQv90Wmo9ynpzAkLwNmKVe I4p9kD1tiEbXUkaMAMM/xBouArc9a/6dmMpiDmDx7hbaEqb7QDQ13vedRsVwxLZPYojMbkfsgJO foJyR4wh6NKLB/byW+/JsV6CpGTSR6SKQgaDpPQkQwgX72WMwgPt6DUcpxzSlLKluebS9ks7HBx RuTimA6wu/mNezIDIreu6UZ9NppyryFwOPnos9Yz7RpXejgUkvQw7p3+Rr3oNB70RKrdppL1/xR 0wFn8mgtVWDRDaYTCPibRCBfi09BzKncQxBVwmnjcCwWlwJ/pODMyqjvO8J+RqPrVSoyXxHP3zW 6j+Mzg2swzuhOnG8VFIw8eq2n0OyDONligdRniY/xOA+KeKTX1 X-Received: by 2002:a05:600c:348c:b0:485:39b2:a47c with SMTP id 5b1f17b1804b1-486fee1af1cmr6282575e9.25.1773951961862; Thu, 19 Mar 2026 13:26:01 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.00 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:01 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 43/55] drivers: hv: dxgkrnl: Implement D3DDKMTIsFeatureEnabled API Date: Thu, 19 Mar 2026 20:24:57 +0000 Message-ID: <20260319202509.63802-44-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov D3DKMTIsFeatureEnabled is used to query if a particular feature is supported by the given adapter. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 dxgproces= s *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); =20 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 *ms= g, if (use_ext_header) { msg->msg =3D (char *)&msg->hdr[1]; msg->hdr->command_offset =3D sizeof(msg->hdr[0]); - msg->hdr->vgpu_luid =3D adapter->host_vgpu_luid; + if (adapter) + msg->hdr->vgpu_luid =3D adapter->host_vgpu_luid; } else { msg->msg =3D (char *)msg->hdr; } msg->res =3D (char *)msg->hdr + msg->size; - if (dxgglobal->async_msg_enabled) - msg->channel =3D &dxgglobal->channel; - else + if (adapter && !dxgglobal->async_msg_enabled) msg->channel =3D &adapter->channel; + else + msg->channel =3D &dxgglobal->channel; return 0; } =20 @@ -2049,6 +2050,55 @@ int dxgvmb_send_invalidate_cache(struct dxgprocess *= process, return ret; } =20 +int dxgvmb_send_is_feature_enabled(struct dxgadapter *adapter, + struct d3dkmt_isfeatureenabled *args) +{ + int ret; + struct dxgkvmb_command_isfeatureenabled_return *result; + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; + int res_size =3D sizeof(*result); + + if (adapter) { + struct dxgkvmb_command_isfeatureenabled *command; + + ret =3D init_message_res(&msg, adapter, sizeof(*command), + res_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + command->feature_id =3D args->feature_id; + result =3D msg.res; + command_vgpu_to_host_init1(&command->hdr, + DXGK_VMBCOMMAND_ISFEATUREENABLED); + } else { + struct dxgkvmb_command_isfeatureenabled_gbl *command; + + ret =3D init_message_res(&msg, adapter, sizeof(*command), + res_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + command->feature_id =3D args->feature_id; + result =3D msg.res; + command_vm_to_host_init1(&command->hdr, + DXGK_VMBCOMMAND_ISFEATUREENABLED_GLOBAL); + } + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + result, res_size); + if (ret =3D=3D 0) { + ret =3D ntstatus2int(result->status); + if (ret =3D=3D 0) + args->result =3D 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 =3D 1010, DXGK_VMBCOMMAND_COMPLETETRANSACTION =3D 1011, DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST =3D 1021, + DXGK_VMBCOMMAND_ISFEATUREENABLED_GLOBAL =3D 1022, DXGK_VMBCOMMAND_INVALID_VM_TO_HOST }; =20 @@ -126,6 +127,7 @@ enum dxgkvmb_commandtype { DXGK_VMBCOMMAND_LOGEVENT =3D 65, DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES =3D 66, DXGK_VMBCOMMAND_INVALIDATECACHE =3D 67, + DXGK_VMBCOMMAND_ISFEATUREENABLED =3D 68, DXGK_VMBCOMMAND_INVALID }; =20 @@ -871,6 +873,35 @@ struct dxgkvmb_command_shareobjectwithhost_return { u64 vail_nt_handle; }; =20 +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, vo= id *__user inargs) return ret; } =20 +static int +dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_isfeatureenabled args; + struct dxgadapter *adapter =3D NULL; + struct dxgglobal *dxgglobal =3D dxggbl(); + struct d3dkmt_isfeatureenabled *__user uargs =3D inargs; + int ret; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + DXG_ERR("failed to copy input args"); + ret =3D -EFAULT; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + if (adapter) { + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) + goto cleanup; + } + + ret =3D dxgvmb_send_is_feature_enabled(adapter, &args); + if (ret) + goto cleanup; + + ret =3D 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[] =3D { /* 0x00 */ {}, /* 0x01 */ {dxgkio_open_adapter_from_luid, LX_DXOPENADAPTERFROMLUID}, @@ -5406,6 +5451,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x47 */ {dxgkio_open_syncobj_from_syncfile, LX_DXOPENSYNCOBJECTFROMSYNCFILE}, /* 0x48 */ {dxgkio_enum_processes, LX_DXENUMPROCESSES}, +/* 0x49 */ {dxgkio_is_feature_enabled, LX_ISFEATUREENABLED}, }; =20 /* 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 */ }; =20 - struct d3dkmt_enumprocesses { +struct d3dkmt_enumprocesses { struct winluid adapter_luid; #ifdef __KERNEL__ __u32 *buffer; @@ -1590,6 +1590,33 @@ struct d3dkmt_opensyncobjectfromsyncfile { __u64 buffer_count; }; =20 +enum dxgk_feature_id { + _DXGK_FEATURE_HWSCH =3D 0, + _DXGK_FEATURE_PAGE_BASED_MEMORY_MANAGER =3D 32, + _DXGK_FEATURE_KERNEL_MODE_TESTING =3D 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) =20 #endif /* _D3DKMTHK_H */ From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f51.google.com (mail-wm1-f51.google.com [209.85.128.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D99B63FFAA8 for ; Thu, 19 Mar 2026 20:26:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951968; cv=none; b=fvyqCP+7MRfzAfS3i06dnKat1mRFK6rLE15+6a9JEB85g59gsdAYJufSTkRebcvD1oq00mamGybpaHOFHvzzVz0AyHE2chsgxY49OfVxGxJPQQVrx4KpdlzpIPuC2h5cgqp9ih+JjjpX2vOiHEdLQDaWn+yWV8GqXINohd3DHUI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951968; c=relaxed/simple; bh=VR58u3V3i58J8N6ZNFVtkIjqDKPXetLd0h+s5znAmcE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c0qLxgZleyPGenchVqY1NUjE8B6lNRaByiFGS0YLleXx2gHBCVSniV11FWt7QSHqiLLr772/RCLIGf6rkoNUyUtaVFdHeTKDcOZa0r8mA8XctDbbjolySQVVSKYIrE6YNdW9VJi3lh5vfR926HXm+zxOUkHNgQIEU910JBhkQ78= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=V2fJl+nH; arc=none smtp.client-ip=209.85.128.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="V2fJl+nH" Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-48540d21f7dso14993505e9.0 for ; Thu, 19 Mar 2026 13:26:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951963; x=1774556763; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=DDHDicT0bUGDGWHfwGKo943zbmk1k4eN+/Sr+skSI6Y=; b=V2fJl+nHWAeNcjSxnuPqlE3ublca6IzhVBTM7dMRwfv7/BlY2AloK/bgJZe4xl3Zag lPYe8Xit+jgAZtbTeOa+RXph1/JCmtBambJtzIRHnpukdTe7+ADZX5dainwMy2+qHN/5 Itr2IvWLxV5vAWdWMhBsUlSed7jlZisSvewG3tPIkfJu8+Gxuwchg/jsNHC0MicmVXRv QyD4DTmJmyisJWeKDFj80HwtGNWI103kkBgkuJyw98RMuUOwTsj1TwAkJhTZJWgtrxFR xIIjGCte1kefmwrAJu5BU1yBCUJxfUBij9U0pZItRbCRUOhzXdvR81zz+PRCJkA/I0/Q tpIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951963; x=1774556763; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=DDHDicT0bUGDGWHfwGKo943zbmk1k4eN+/Sr+skSI6Y=; b=dEP0SrQLCGavX22f1E1nNsctsurGqyXsejkOvZCKAj/gLvzq/EfW0PCNtmlAG8hxRt E0nPkErzPEvcZMEIduuIfEmCiJJ/Jxpq0PU1CidTjE8ix2/ZntKLmOfNPNUfMsta/Bff oBVefVQCjvul9APVqaUi+IjfegWS4eYeWRWqzeOUEX/RYIjtz/MQs0TFzZ5CiAkNKCMd bdV6eY4tT/SuZLz8W8n5oKsHaJQFARQETdrfwG6o9Sf2aenNKmuQqYM/hKTW55jBorgN IBc3JuCvO4TllbH6SPKL7TszmWO+FtQhQ62sl6AQw22NGTk+xIxAW0lVG40dVmKE8qgA aCiQ== X-Gm-Message-State: AOJu0YyaL/gUXU4vt+WIOasfIdJfzwrsBq3tF8rOoZUTt1MveRZ7BBcg FrhnVwtXMalAgF+XZ5JL31EIiJ90YXA7lxRNbfI3XGVo47KR7GtoJkjJ X-Gm-Gg: ATEYQzyIBxEu1/2a7W+mH/BGKfKI7EB7EueKZOY6V9qCkhLGKMLxrdN//2sVoAYtjg4 Mp3GHBUIu3AzDyh0iDHstCHh4933lodPugg58Knqw/UvhNqSilgVyK4phPNV+oJ15/ZmJsJdL8O mbJBEegI7tJRwgMT2clFMMaX0uPbHpb5ahaxXMDsXyi3BaasVjl4oGXuboHah+IsD/49rU5FQnG Wy9tXk3wAaqctwFpvaKN1rmFgirWIkfV6w+u/0G632o+U5sj+TdWxtPpkNG2Gi+yBYxd9blEQHz /1zEQe3m8G4gcnK1AIXopiTF6AMzDYAUeiI1sKF48Iuxh3X3YEoFBlX+qhv5ji5+jM93Lx1BRO8 rGxJ7iILAqZPQXtkwvjTqfXjb8vwOcIAyMlhER9NgvfGXH0H/JqC3STD6Pue0gzga8z1FFj/eXU 5PP1YNrqElA3ufItu5MwTMX5XhmeJv7aKbIQK37xJmUxJBCW3W X-Received: by 2002:a05:600c:34d2:b0:485:1878:7b8c with SMTP id 5b1f17b1804b1-486ff029163mr6284935e9.18.1773951962928; Thu, 19 Mar 2026 13:26:02 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.02 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:02 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 44/55] drivers: hv: dxgkrnl: Implement known escapes Date: Thu, 19 Mar 2026 20:24:58 +0000 Message-ID: <20260319202509.63802-45-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Implement an escape to build test command buffer. Implement other known escapes. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 dxgproce= ss *process, =20 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 =3D NULL; @@ -2203,13 +2204,18 @@ int dxgvmb_send_escape(struct dxgprocess *process, command->priv_drv_data_size =3D args->priv_drv_data_size; command->context =3D args->context; if (args->priv_drv_data_size) { - ret =3D 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 =3D -EFAULT; - goto cleanup; + if (user_mode) { + ret =3D 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 =3D -EFAULT; + goto cleanup; + } + } else { + memcpy(command->priv_drv_data, args->priv_drv_data, + args->priv_drv_data_size); } } =20 @@ -2220,12 +2226,18 @@ int dxgvmb_send_escape(struct dxgprocess *process, goto cleanup; =20 if (args->priv_drv_data_size) { - ret =3D 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 =3D -EINVAL; + if (user_mode) { + ret =3D 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 =3D -EINVAL; + } + } else { + memcpy(args->priv_drv_data, + command->priv_drv_data, + args->priv_drv_data_size); } } =20 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 } =20 ret =3D dxgadapter_acquire_lock_shared(adapter); - if (ret < 0) { - adapter =3D NULL; + if (ret < 0) goto cleanup; - } adapter_locked =3D true; args.adapter.v =3D 0; ret =3D dxgvmb_send_change_vidmem_reservation(process, adapter, @@ -4299,10 +4297,8 @@ dxgkio_query_clock_calibration(struct dxgprocess *pr= ocess, void *__user inargs) } =20 ret =3D dxgadapter_acquire_lock_shared(adapter); - if (ret < 0) { - adapter =3D NULL; + if (ret < 0) goto cleanup; - } adapter_locked =3D true; =20 args.adapter =3D adapter->host_handle; @@ -4349,10 +4345,8 @@ dxgkio_flush_heap_transitions(struct dxgprocess *pro= cess, void *__user inargs) } =20 ret =3D dxgadapter_acquire_lock_shared(adapter); - if (ret < 0) { - adapter =3D NULL; + if (ret < 0) goto cleanup; - } adapter_locked =3D true; =20 args.adapter =3D adapter->host_handle; @@ -4417,6 +4411,134 @@ dxgkio_invalidate_cache(struct dxgprocess *process,= void *__user inargs) return ret; } =20 +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 =3D *args; + u32 buf_size; + struct d3dddi_buildtestcommandbuffer *buf =3D NULL; + struct d3dddi_buildtestcommandbuffer *__user ucmd; + + ucmd =3D args->priv_drv_data; + if (args->priv_drv_data_size < + sizeof(struct d3dddi_buildtestcommandbuffer)) { + DXG_ERR("Invalid private data size"); + return -EINVAL; + } + ret =3D 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 =3D sizeof(struct d3dddi_buildtestcommandbuffer) + + cmd.dma_buffer_size + + cmd.dma_buffer_priv_data_size; + buf =3D vzalloc(buf_size); + if (buf =3D=3D NULL) { + ret =3D -ENOMEM; + goto cleanup; + } + *buf =3D cmd; + buf->dma_buffer =3D NULL; + buf->dma_buffer_priv_data =3D NULL; + + /* Replace private data in the escape arguments and call the host */ + newargs.priv_drv_data =3D buf; + newargs.priv_drv_data_size =3D buf_size; + ret =3D dxgvmb_send_escape(process, adapter, &newargs, false); + if (ret) { + DXG_ERR("Host failed escape"); + goto cleanup; + } + + ret =3D copy_to_user(&ucmd->dma_buffer_size, &buf->dma_buffer_size, + sizeof(u32)); + if (ret) { + DXG_ERR("Failed to dma size to user"); + ret =3D -EFAULT; + goto cleanup; + } + ret =3D 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 =3D -EFAULT; + goto cleanup; + } + ret =3D 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 =3D -EFAULT; + goto cleanup; + } + if (buf->dma_buffer_priv_data_size) { + ret =3D 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 =3D -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 =3D 0; + + if (args->priv_drv_data_size < sizeof(enum d3dddi_knownescapetype)) + { + DXG_ERR("Invalid private data size"); + return -EINVAL; + } + ret =3D 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 =3D build_test_command_buffer(process, adapter, args); + break; + default: + ret =3D 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 *__u= ser inargs) } =20 ret =3D dxgadapter_acquire_lock_shared(adapter); - if (ret < 0) { - adapter =3D NULL; + if (ret < 0) goto cleanup; - } adapter_locked =3D true; =20 args.adapter =3D adapter->host_handle; - ret =3D dxgvmb_send_escape(process, adapter, &args); + + if (args.type =3D=3D _D3DKMT_ESCAPE_DRIVERPRIVATE && + args.flags.driver_known_escape) + ret =3D driver_known_escape(process, adapter, &args); + else + ret =3D dxgvmb_send_escape(process, adapter, &args, true); =20 cleanup: =20 @@ -4485,10 +4610,8 @@ dxgkio_query_vidmem_info(struct dxgprocess *process,= void *__user inargs) } =20 ret =3D dxgadapter_acquire_lock_shared(adapter); - if (ret < 0) { - adapter =3D NULL; + if (ret < 0) goto cleanup; - } adapter_locked =3D true; =20 args.adapter =3D adapter->host_handle; @@ -5323,9 +5446,9 @@ dxgkio_is_feature_enabled(struct dxgprocess *process,= void *__user inargs) { struct d3dkmt_isfeatureenabled args; struct dxgadapter *adapter =3D NULL; - struct dxgglobal *dxgglobal =3D dxggbl(); struct d3dkmt_isfeatureenabled *__user uargs =3D inargs; int ret; + bool adapter_locked =3D false; =20 ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { @@ -5340,11 +5463,10 @@ dxgkio_is_feature_enabled(struct dxgprocess *proces= s, void *__user inargs) goto cleanup; } =20 - if (adapter) { - ret =3D dxgadapter_acquire_lock_shared(adapter); - if (ret < 0) - goto cleanup; - } + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) + goto cleanup; + adapter_locked =3D true; =20 ret =3D dxgvmb_send_is_feature_enabled(adapter, &args); if (ret) @@ -5354,10 +5476,10 @@ dxgkio_is_feature_enabled(struct dxgprocess *proces= s, void *__user inargs) =20 cleanup: =20 - if (adapter) { + if (adapter_locked) dxgadapter_release_lock_shared(adapter); + if (adapter) kref_put(&adapter->adapter_kref, dxgadapter_release); - } =20 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; }; =20 +enum d3dddi_knownescapetype { + _D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE =3D 0, + _D3DDDI_DRIVERESCAPETYPE_TRANSLATERESOURCEHANDLE =3D 1, + _D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE =3D 2, + _D3DDDI_DRIVERESCAPETYPE_BUILDTESTCOMMANDBUFFER =3D 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 =3D 0, _D3DKMT_ESCAPE_VIDMM =3D 1, From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wm1-f47.google.com (mail-wm1-f47.google.com [209.85.128.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E88643FFADF for ; Thu, 19 Mar 2026 20:26:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951968; cv=none; b=UTPS1PndgSsAoj6pdiBi7Dw/GVJIn5pzpvdUW+QTLKL0+G+hx6v5hgS8IFl36OdHxXr/t8kD9Hg7m1Sis3F07etgk0gc3DFsi00M2oo93lZdB56c7xJw5NRiGyyM700reW3W/gy0mtro6Kq8EnAte+f3CHGRVQhMHNLxrDxphpQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951968; c=relaxed/simple; bh=zMPjUJp3qaN20qEcVMXOtJ/uhNBq3nlGbiLzRom/6l0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=exjFleaUf4LB0fsSH9soGtDWUnVbMquw4EX84ikns0/NAbgDqaxkJonavUab4YGDx701zlSsqOPvHK/JwDvNyY7rs9hT9PSJYgKUodp9yjBnnnBMMwWKJavqWBz20BJYSKv/5JGOIEPz7LL7/6qI7Zqv/sHhxh/s7Gyb7t3pjSE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=RcX6HoIm; arc=none smtp.client-ip=209.85.128.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RcX6HoIm" Received: by mail-wm1-f47.google.com with SMTP id 5b1f17b1804b1-486fb439299so9165785e9.0 for ; Thu, 19 Mar 2026 13:26:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951964; x=1774556764; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=O2tY7so1VAcy4ANuQwbb9ijas9+JYVH0PRQMX4x27sM=; b=RcX6HoIm/KKfcn4Aj2y6zGN2IPhvby3WSMnnqYpWa9gTKG8gP+9Zcg2WkS0E0c6jaJ XcEa2sOVnOL7PceVt4SjO208ZEtLQdvJY+D3oyZ5fFwRhxLkIOtyhtgTKLHfBXbizpQ4 YRh/GG5STsBCOGfVGeguDbvlm8VQJ4KRFsl34hM7Uhk/4QvnnxjjB3MAV2Oc4nQgMcpU kBNAg4br7NZfLlbj4GXWhZ2eiCn9cn62gJXteQHNONSj0tybumgX2gVa8n6XIffsdkCZ FHpl+vDVz+HLCXyn+ddTQl5aU4iaHqSlhnucRKy2x/vJEmCiwpzeZTd5BKWD7y8xfmxy ocCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951964; x=1774556764; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=O2tY7so1VAcy4ANuQwbb9ijas9+JYVH0PRQMX4x27sM=; b=kmhEVXqv5J7mbvVmsnJXJmSmq3re8TvJiaSxBZJyei8QQHp5rg3tJLNrPIXGGtdbF1 yS0TUaRuyzIYhdEzJaOXZwcYK3gRLyMrlCekSM8ARvcHyIO3Lcx5JBSnjI11SCe/le5m Jtc4nf/7rlyW+f8wAkfohvyht7b+rxn6AykFlzURYNwF0c3KNpylo9/Tgz8oPtwvUmHl cuHOh39DIRUoEymFJD6E2IXmbPNhrYvXjDbhzaP+TyJKPOCqVILu86wFrRxG9TST4lUq Juu3e+nfAGYjdscp0h+Cbofnj3VpbFVYnABh221fdO7d98V0Q49UWls81aHDQSV7IncL SymQ== X-Gm-Message-State: AOJu0Yy86dwecH2pCxJMEBBeyJ2NDrRDOhqH4jgYf+YiD3Hfbz6VCF37 zyGDml9/J8iV6nOnlvGKP93UAReXKWZESaPDpZGHEQ2aG6lnu1IqwzH5 X-Gm-Gg: ATEYQzxqDbqxlk4qDEYbbrsOFsj/epzyM0PgN5WT+CQum1bMd0luza7PODJeel8Ywdj f8G/05S5aioU/oy/voiuhOZwMUHkU+FGex99r7t99CqwlZCqDpki1vombLgILBtc6eNtWX6gaZ5 qZkBjOK/aOwCi6hTmBQAXC8frteuDcsnd2MNk8yANyaFPVImGfQURhguejoBZMzpdcXjQdXw24d 1lHoGdUiu2GPcSGzNsrwc4vQ1umfr1p4+JL3x/k6CDn/oOdEhwUkBnJWddhtZG3dNdVGKpImSFj tEWXV42LNQM/D6V10UwSCtPJ+Cae/KxylgpHdx6iNrRfTQjnc1x7YoJeSr3PTwBjDIxC3KBDXbY x5EWlp32JoXADXzjfGBvnBuIFDJnE2FMk7/QwmziwQwgePgHPZIk6/bN/Z5Q0IO6Jg1iDQR0kEA nAxonE24TNg62jQJ7lOBuICSz6sqHv9AjOQVCvga9lBDUXWD/STeA0Ip+A2+A= X-Received: by 2002:a05:600c:4705:b0:486:f9aa:2b57 with SMTP id 5b1f17b1804b1-486fee0d6d4mr6935405e9.16.1773951963960; Thu, 19 Mar 2026 13:26:03 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.03 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:03 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 45/55] drivers: hv: dxgkrnl: Fixed coding style issues Date: Thu, 19 Mar 2026 20:24:59 +0000 Message-ID: <20260319202509.63802-46-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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/dxgadapte= r.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; } =20 @@ -1225,10 +1224,8 @@ struct dxgsyncobject *dxgsyncobject_create(struct dx= gprocess *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; } =20 @@ -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); } =20 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, st= ruct hv_device *hdev) goto cleanup; } =20 -#if LINUX_VERSION_CODE >=3D KERNEL_VERSION(5,15,0) +#if KERNEL_VERSION(5, 15, 0) <=3D LINUX_VERSION_CODE hdev->channel->max_pkt_size =3D DXG_MAX_VM_BUS_PACKET_SIZE; #endif ret =3D 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 *pro= cess, 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 *proces= s, void *__user inargs) } if (event) eventfd_ctx_put(event); - if (async_host_event) - kfree(async_host_event); + kfree(async_host_event); } =20 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 =3D 0; =20 - 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; =20 - for (i=3D0; i < ARRAY_SIZE(ioctls); i++) - { - if (ioctls[i].ioctl && _IOC_NR(ioctls[i].ioctl) !=3D i) - { + for (i =3D 0; i < ARRAY_SIZE(ioctls); i++) { + if (ioctls[i].ioctl && _IOC_NR(ioctls[i].ioctl) !=3D i) { DXG_ERR("Invalid ioctl"); DXGKRNL_ASSERT(0); } From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 241804014B4 for ; Thu, 19 Mar 2026 20:26:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951969; cv=none; b=D8wq+fg8pCUD7E7F9qszufk8LMnCQSh84vI4lYvfpcQPlNnSq866ZTi+jeczfTS/qdih0d4HRAAsRga8DHWHilLTzEQAbRz4p98NFnllHcYF4vFklHYfCleGBB+cpsfiy1KONu0IIZSMazlRGZVF/JPVLqxJSG8CxEW9ScTAfdw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951969; c=relaxed/simple; bh=x0xQqLTzkCRNQUot1j/UYCtbtBAAOsk8jYrEIs7+tYA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UyqxnVx9FYbuStOaxv1eiUNxlAf5GYIYf9oemh72rcfHcdFNfnoJ+dv4Gm8qFCXeq/h6LbJG3yCeAPUktz0du6QokxAGaivvkFFh1bSXzut1n/T5lDhJRwjUFKRpO97BCB7a83NpG7aEcDD5m3yDdX31Dp90sqpIUNbHJhS8hl4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=kYaFFPkz; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kYaFFPkz" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-439b2965d4bso1015584f8f.2 for ; Thu, 19 Mar 2026 13:26:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951965; x=1774556765; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WDpJy6eUcHO0PuqsrcmnUFgysvSCvcBPbvdavy5mnIc=; b=kYaFFPkzLsm11BsjOcgvhswfSGK/XASDqTtHczFx1AF8Vn9krwciAheoAbRzkYgCbg J2kLCjgfafPyVzmP8LIdH1PQ2KfTW4IojSeMXkbemgFGBhyoIM70Fi2ogPKfkljO0jzc EsSZXNQJlPsTveXyECXdGtoYrYMc+YXwkqljkcI3r3+RCOLNnOU/WtwwPeHP44YML1Y/ CrILTgiXWMVq5oPVOI7g/e/oRlzljOwX9EsY/jG32GbmLxbOuj1MkZ/2A463iZjdECYi V47z3FFQSirr0rlS03PxgcvyaFmQPIZMsioK3t9tPRKJSDmhC+xcTXShO5NnghPo63pU NG+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951965; x=1774556765; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=WDpJy6eUcHO0PuqsrcmnUFgysvSCvcBPbvdavy5mnIc=; b=AZgjslErxOet8NMa4oW6c4VK7OePhbLfMbxCU6Ak6On7J2m17X2rOiCkfXU/dc6xTF mk/tdudfKRv4Q+9RmCwWFElmNXwBCl8ShH4/bGPbQ4+G9wya8ZwYxMmyGicU2r55CkGp LH6FAm4Tuem0Wbu9mtoQXs16js9UTj/D7G8URSFmoDiW0ojWjqkoDmLrB+mMLhh579wr Ecx2Ksg+U2ysCiJENR17Li5+pgrqAcTKuKpmb7YuZx24EtYygx2IOP4tm7zH7WfPn35q FuHs0BlxLH4uktbfkC76vxlguIjb1jdTgL/7tg2YnRUQMio6fsqojTO0I36/EnkvXzsO HN/Q== X-Gm-Message-State: AOJu0Yx1s4pRuyfzOoLSX2lsRrBlm1fMZN2P5p+02srGztizwB64OF5W l6oXIg/fn7q60OLyb+jFRwnU1zy/AvUL/rviaR6rU0ltcKNRZ8oRFHys X-Gm-Gg: ATEYQzwYRJOSR8aqiv/Q6M3mi8x7DlFJCCorcFrwDDIDAsMv8KHYuCJBY6FH9z3NMEq I2/9Ix4HBNqJWD1Cr9Gf0R41XTzhrWZz9VhOoiNiA5hJ0+UsbIVbu6KBuReKwmo6e79yk/ZRw44 +PW1eW0wQdAURA5v07JPNR3DEY9N3YowSiIvcX51ztxA+OjEuPNcQnHeXgDSqOaCdUWoghfgE9O gXAerNjPp4EwMlGnVu3+/TPzWcMAnljo4/Kx1Hz+giF0kygU/plLfi2g2i59FcERE7QVADQHnm9 azAm66cq27Zr0Ya5S53akfIzpFtUV0I0o5D3nqv9nNN9V3QZpKKsXFECPqM4cAFt587P59UwOS0 QK6IY92pGzJqjk4d7zaJXPIxFdokrT5LB/a8Hq1QwKkishpqUcRbDQe6dbA3kqA51JU+LoUexAG CrEnmQhmRql2bFBAbxz74QG3iSdu6kYttkbY+CfLU7VpoPD8uI X-Received: by 2002:a05:6000:25c7:b0:43b:468e:3d78 with SMTP id ffacd0b85a97d-43b64291a02mr1126082f8f.52.1773951965173; Thu, 19 Mar 2026 13:26:05 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.04 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:04 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 46/55] drivers: hv: dxgkrnl: Fixed the implementation of D3DKMTQueryClockCalibration Date: Thu, 19 Mar 2026 20:25:00 +0000 Message-ID: <20260319202509.63802-47-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov The result of a VM bus call was not copied to the user output structure. Signed-off-by: Iouri Tarassov [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 dxgp= rocess *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 =3D {.hdr =3D NULL}; + struct dxgvmbusmsgres msg =3D {.hdr =3D NULL}; =20 - ret =3D init_message(&msg, adapter, process, sizeof(*command)); + ret =3D init_message_res(&msg, adapter, sizeof(*command), + sizeof(*result)); if (ret) goto cleanup; command =3D (void *)msg.msg; + result =3D msg.res; =20 command_vgpu_to_host_init2(&command->hdr, DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION, @@ -1981,20 +1983,20 @@ int dxgvmb_send_query_clock_calibration(struct dxgp= rocess *process, command->args =3D *args; =20 ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, - &result, sizeof(result)); + result, sizeof(*result)); if (ret < 0) goto cleanup; - ret =3D copy_to_user(&inargs->clock_data, &result.clock_data, - sizeof(result.clock_data)); + ret =3D copy_to_user(&inargs->clock_data, &result->clock_data, + sizeof(result->clock_data)); if (ret) { DXG_ERR("failed to copy clock data"); ret =3D -EFAULT; goto cleanup; } - ret =3D ntstatus2int(result.status); + ret =3D ntstatus2int(result->status); =20 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 *pr= ocess, void *__user inargs) &args, inargs); if (ret < 0) goto cleanup; - ret =3D copy_to_user(inargs, &args, sizeof(args)); - if (ret) { - DXG_ERR("failed to copy output args"); - ret =3D -EFAULT; - } =20 cleanup: From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1CF003F99FB for ; Thu, 19 Mar 2026 20:26:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951970; cv=none; b=k6FRkYhamIBLf1jJ79j03L2xTieMrgKAAqOMX1GaZzHjQkpepOWdi7lVw5hU9OmobYzEVBgwYyOb40p58YBoCPIGMivEOA6IkzVktsLvl74K0KyosWroHEZ6P/1YCt7vwtswlD+mAbcxyobA20TR2wsqj9j6sOCMjMD52bSxgR8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951970; c=relaxed/simple; bh=aGsCqTmbio2gk0tJU8PH4eYhSnMzryFGj3iv/ce5q64=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F41uuXRKNVBO7RHh7K2u5DyjLFB+4PE7oslwm4wQ3nVyKpE+PqPxHua5XqRiVcqyJqiJHde0ZdqT870/sPWG5rt1UTIzUB6Kr76xqXzfvMtt8PvhbaUxcxP8pzS3h2aVR86wmr7+JCHR0Fg+rC3dBdBT6FaQva5om3bFsgA6M2o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=RSMGK9jH; arc=none smtp.client-ip=209.85.221.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RSMGK9jH" Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-439c9bdc1eeso1086119f8f.3 for ; Thu, 19 Mar 2026 13:26:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951966; x=1774556766; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=L59fd8D5hkyMG2nQhO698xghueZKtfuG5YRQ+ujsUlI=; b=RSMGK9jHPDnRXNiCSjUMrGkKSJFzZPMFaq4eJCIt9D7cFkqSTfkur/gji7W9GxVTM6 LeXzvqdtq6jEd1LHbKMN2sku6V7mzVcY/lcPZ+2/oefxtZkR4iFApzJRgbm04Y4DsLlF +GRt6UIybe2gjz/RVGREklULtAV+f7W5g1tdlOmmoz3L8CQDNAQqkXRRsrAjottAlhfZ 2m08amXqv6QdebZyD7E0Arl7z0U+xkQM2cD/ZLEgTgcXjRGShWzI9axoAGwY4SaK54Qw TRVv1keIBmyY+VQMr4j+OVz+sWKoHeMxIzkIgpKLbxb8f+O5tqB7B/cAHaw/BaoApO0/ KY0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951966; x=1774556766; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=L59fd8D5hkyMG2nQhO698xghueZKtfuG5YRQ+ujsUlI=; b=GMGq6vzbN6OkyfH0+YL0ZVaLRQBIaFgCsZxT3LI3QxpiGT2UGGtILqhdGRF7NcdrvK +ExD9XxKBwyo46eZivHeC0FM/CBee3W/xtXLVD31qMb+CauxSU2YcR7/Qg1dxmjWfM4j aV+I9CJnuHVQhj8PUAFHHLh7ektOsJl4uYdg8K72co3Y3xGroPKYSvoh4jKvztHCfhdl vd1RvXzHtoZp+kLlC3f6hmqRIvWmrTgyqcuktdtLywLkLpAvll3tIyZ3XPgRfSLiTb0J oUNTveE70DXuaMAwBOQeoY35pxnW3ohUxniQ8Gb9EAFD5pMsPWNmnz9cyADYv4krahfg oq1A== X-Gm-Message-State: AOJu0YxeUWybdbDcK4K1nHVLoSEi0OTWUGXU+IdJioOZ26nrdlAwf/5u s/m0NWiYHlABaxpYSA5H/wfRde8uhX5ndT7AnluYzEfvnoV3GM+F3xAT X-Gm-Gg: ATEYQzwKWsungCJmfBnG8q/uREJ9pWWiWNNUWQTWppUoTb0l81ax50Zwx8EPVRAmWLT yZkLMsjifWmWKPntP2rHEMl9w6iZdT8vleZWgyUmRkH+KngYgJ37WRZwnReSvOf+aC80MvzMa3u jqb5vozjQ3v7FgC3EOolZNA4RfA3zQyP7Lt+heaSutmomn/VyaAHIKhIQ96oBKOQLxJcz7AQ6D6 1kLjs5qEvwKKyVruUWF7oJ5PE/kD76WcJMPqZH4GnP8LECLis2buKBL+9UBycqR7fGcU2TxdDm1 WWpTRc+vP0KWYNI1fllj0medm6BcLMYc7foy7kTYSDLBJrr+7w4PhGLb3TJWFJXCh3VJnLJdgdD 7n9TYWUjh8qDnqek1oQCZfnrcVDDa1DoDwyjuRF63W+YdzY3PVO+qII69gMZdIOeGwLr9S2kbJH suiAHbub5AFUP0n2u2Dt+05nHZwqZDwT4cgQ4HNorWle5jePpl X-Received: by 2002:a5d:5d85:0:b0:43b:49a1:8ace with SMTP id ffacd0b85a97d-43b6427b2e1mr1272743f8f.51.1773951966444; Thu, 19 Mar 2026 13:26:06 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.05 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:05 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 47/55] drivers: hv: dxgkrnl: Retry sending a VM bus packet when there is no place in the ring buffer Date: Thu, 19 Mar 2026 20:25:01 +0000 Message-ID: <20260319202509.63802-48-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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 *channe= l, struct dxgvmbuspacket *packet =3D NULL; struct dxgkvmb_command_vm_to_host *cmd1; struct dxgkvmb_command_vgpu_to_host *cmd2; + int try_count =3D 0; =20 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 *chann= el, list_add_tail(&packet->packet_list_entry, &channel->packet_list_head); spin_unlock_irq(&channel->packet_list_mutex); =20 - ret =3D vmbus_sendpacket(channel->channel, command, cmd_size, - packet->request_id, VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + do { + ret =3D 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 =3D=3D -EAGAIN) { + usleep_range(1000, 2000); + try_count++; + } + } while (ret =3D=3D -EAGAIN && try_count < 50); if (ret) { DXG_ERR("vmbus_sendpacket failed: %x", ret); spin_lock_irq(&channel->packet_list_mutex); From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f48.google.com (mail-wr1-f48.google.com [209.85.221.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1F9ED3FFAD3 for ; Thu, 19 Mar 2026 20:26:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951972; cv=none; b=FgG1mSDwIk9HAMdvXJrlOizttbk28/sx8mP3EwjKYLN5CAahyrf5X01fP/l8nxkX229sqQrKe4IdwcwMlHkwsJWHjnLvblofMPhIbCJl4HPDIPau2llU6ezu5VMFZzEcbgSecD881Fg0Gaz+vUnOqW0heMc9y1BRGKeARMKJ1Cw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951972; c=relaxed/simple; bh=BmylmSxYXC5N3jk9/TNR/sEYojyD8Hf/GASHP6Q5wi0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HyeOyz6CfDmh6Ek6cVz/9qw2kJnnE1BUqAxHecgn3PuoE3fNi9y6AV6xy+4dVjPLWlpv6rs63JsaZ2mSDomjLieeD8E+xy6AdTKEqJ6rrCtyhOy79VCZOI9+NBbis6f7TnOXUJF+J6WKePHhqoz/P1/TntP4wAtWLJFs13e29a8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CZEEOcey; arc=none smtp.client-ip=209.85.221.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CZEEOcey" Received: by mail-wr1-f48.google.com with SMTP id ffacd0b85a97d-43b44c0bcdbso1003314f8f.1 for ; Thu, 19 Mar 2026 13:26:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951967; x=1774556767; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=kVfSYosL52eK3asK6+0i4KG7DrtDbq3VH+01ZAcM9Cc=; b=CZEEOceyiLZBbBuf/kEqJfwRt8jE3+7L1VXL7ms5gdFNa78C67P3GW3usJEd32PP2G 2ORY3yHlD/JbJp+ud1CVWU4AxP5q869MvEfXK7V55uoMR3obGfSjAWRxnLwTANEcZgPM VSpDzUTDnuJDYS3thKbeRShH6ztQlmsPb1IYfvNzbvqLl3kdnyp9/TEcoj7vFT0mQGeg GdnfbXxwwjSP4whLMYcRvze9Jzkk2PAdwpPmp7tCpvNOve/JjjKHGsXb8nA3G83ZNMid 4rBntbxU9cmUjJ0GcGkpIrnlXbw0exYWz9YLjuU4MAmmDS7Qjx9dLzuvqAqTm+uq2sHh kQ7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951967; x=1774556767; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=kVfSYosL52eK3asK6+0i4KG7DrtDbq3VH+01ZAcM9Cc=; b=C/3+E7Rs6RD3fTQ40a66YKTu+onZvpfj9f+f2TZR7D09jaOY1IC27R1QgRijZAw3OL DkYUE0tSUaJIk3Tq9/Hy4VP1U4DqSLftEc+kpF4uGNIUpSIWpc+4t3GtxUScTRem6C8Y 8lXxRJvny0s7qxLe+Fy26drOTgoEpH67XQmWl34g5SP0dwcG38XPy3qa1DG/dMcv0yMe 7x2VjELCl0xncywtFjVIZWWmOxwLCyWVP23iARaf7L6/f+AEEHIQ/OLF2sbTEUItCJI7 KmtLh+qFJwDTyaugiBNvrr0Z21FmTR6xfKR2EjF7UZ4oke6My0dRVwtQzS054WH2H1CH ZyRA== X-Gm-Message-State: AOJu0YzKu24HNZM3ULpYA8F0hkJySrBAmKMFLTDlSZz0+g8k2T2z+f4P LKfvwRLhapU5H6TArFfFv5tMo6K1l5SgiXnWV0fvHMsfdwatWg5rO/v8u4MfgP+dLbM= X-Gm-Gg: ATEYQzyvT2migKta9c+tMyiYNMonwOx+M9+YSD5FyT7PcXnDhswMPjx72x+e56uSo2Y qEB8I1I5N3NyQCd9hgRjaHZFwBU6a3+df/xHGBJNA9XcUbvEHyNrzAippKewvgpqt2mgqbkPB3N 9if/a+sRGXD079coQy6hXdZ+pLOhZMJxigrFhfzJvHeQf3skd44G0Hkwc+VaFcwwOYMivyp6n88 WxT3P6coVWaWaNWyMlEsFXlQ72mT2pm3+KSAd3ShEFj9QO02dDNMa/9GbYs57uYmiI5M3sVujKy FJyNVGAxtlhDe1NTCHkrbrcxZxfGvTMa5zmXBurkpYV2wo6YWSfdPc+qrtmUS7/3JwXhdUpEA5y YQCFeO6gCakI2LbFn7Zx5BI7eHHMa4WcqpbmDBZ/3399qcYyy3FJLBQTxGgsPmtx6TBj1aUHPre EfJjDHwjkpDBOJ3Yf/LVH8sKqbOXS2DRvnGPtEW0bT8OoKDtUM X-Received: by 2002:a5d:5f54:0:b0:43b:3d4f:e17a with SMTP id ffacd0b85a97d-43b6426d59emr1246871f8f.37.1773951967410; Thu, 19 Mar 2026 13:26:07 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.06 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:07 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 48/55] drivers: hv: dxgkrnl: Add support for locking a shared allocation by not the owner Date: Thu, 19 Mar 2026 20:25:02 +0000 Message-ID: <20260319202509.63802-49-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- 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/dxgadapte= r.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); =20 +/* + * When a shared resource is created this structure provides information + * about every allocation in the resource. It is used when someone opens t= he + * 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 ob= jects, * 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 dxgsharedresou= rce *shared_resource) u32 data_size; struct dxgresource *resource; struct dxgallocation *alloc; + struct dxgsharedallocdata *alloc_info; =20 DXG_TRACE("Sealing resource: %p", shared_resource); =20 @@ -409,9 +410,10 @@ static int dxgsharedresource_seal(struct dxgsharedreso= urce *shared_resource) ret =3D -EINVAL; goto cleanup1; } - shared_resource->alloc_private_data_sizes =3D - vzalloc(sizeof(u32)*shared_resource->allocation_count); - if (shared_resource->alloc_private_data_sizes =3D=3D NULL) { + shared_resource->alloc_info =3D + vzalloc(sizeof(struct dxgsharedallocdata) * + shared_resource->allocation_count); + if (shared_resource->alloc_info =3D=3D NULL) { ret =3D -EINVAL; goto cleanup1; } @@ -429,8 +431,10 @@ static int dxgsharedresource_seal(struct dxgsharedreso= urce *shared_resource) ret =3D -EINVAL; goto cleanup1; } - shared_resource->alloc_private_data_sizes[i] =3D - alloc_data_size; + alloc_info =3D &shared_resource->alloc_info[i]; + alloc_info->private_data_size =3D alloc_data_size; + alloc_info->num_pages =3D alloc->num_pages; + alloc_info->cached =3D 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 =3D 0; struct d3dddi_openallocationinfo2 open_alloc_info =3D { }; + struct dxgsharedallocdata *alloc_info; =20 hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL); ret =3D hmgrtable_assign_handle(&process->handle_table, resource, @@ -5050,11 +5055,15 @@ assign_resource_handles(struct dxgprocess *process, allocs[i]->alloc_handle =3D handles[i]; allocs[i]->handle_valid =3D 1; open_alloc_info.allocation =3D handles[i]; - if (shared_resource->alloc_private_data_sizes) + if (shared_resource->alloc_info) { + alloc_info =3D &shared_resource->alloc_info[i]; open_alloc_info.priv_drv_data_size =3D - shared_resource->alloc_private_data_sizes[i]; - else + alloc_info->private_data_size; + allocs[i]->num_pages =3D alloc_info->num_pages; + allocs[i]->cached =3D alloc_info->cached; + } else { open_alloc_info.priv_drv_data_size =3D 0; + } =20 total_priv_data_size +=3D open_alloc_info.priv_drv_data_size; open_alloc_info.priv_drv_data =3D cur_priv_data; From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8C934402B93 for ; Thu, 19 Mar 2026 20:26:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951973; cv=none; b=dGDAqP7tvbKF6Ex/1XsUEEQ0vDOkbHybt8j+DhQuEeidEgtXgsZiuJCZRmgFb3SnVEV2VrwXQXHzSIaTN0dzusPIXrNgWicmpwyQ+R0NjRyY8zmMKc/GIvzEbadq6FJKxFp1s3ok7Bm88xLr/wu6tyAjJdLjUZcl7IDd9C1Bq10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951973; c=relaxed/simple; bh=LFLCyuKa/ngNOlQyHMH67L9xJ7S+T7/bhafBPLwr5Os=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FZmk4luP36QLzHUxo4K6XVkvmh7eq2Lx4CcGe6VL1afYw2cc5I2tFCHWvbVomBUCFrE2snlP3/eSGfkV5fDlAw3IFTYhM6S3evYfsyM2WT4/bQ+u7zJefVJLeJzGhLMs4eu2iMmmWWN61fgWdHENb/5NmVob9xj38KmBjiMYWuw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ggnRzfk/; arc=none smtp.client-ip=209.85.221.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ggnRzfk/" Received: by mail-wr1-f46.google.com with SMTP id ffacd0b85a97d-43b4fd681c2so1151221f8f.3 for ; Thu, 19 Mar 2026 13:26:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951969; x=1774556769; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ALSozRz7iDmiBySUPyDVWjPDIGIexogo2v+RuRQMcPw=; b=ggnRzfk/Y8iVr7rrCCHBnOHwnzhneIBnNGHMmUKLS319CPtlL0ReDnnZazHwwcGdoj pLxHSG0O/VvsZFNuA9iedRac9zloQSGAGQsKCHweJVYKTLOgZsq3MzY5Xw4p2HgrDxt4 /ZoAb8a/RRRowEh3qXpCjn7GfgE+Owgb1YQQJptYV4SoSQYjxTvOL56ktvc8zstJlux1 b32hLCykE1QpEWkHEBuQhJ1Nv7p8WzG39FzamiLrn+0WdyTqUn0VWR2cmyfJGfXSls7E kpucvyQG+hjJGV2WWBbYeFSu78cIWKwmX3b19UhpHOgpIYORMyrNmvOhbXHZHi+3Az4V xtEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951969; x=1774556769; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ALSozRz7iDmiBySUPyDVWjPDIGIexogo2v+RuRQMcPw=; b=XwUVfcS2zNcSAqSXGUmMSM1rex26EMrVSNtaMnG4xhWGLaLIWRMHpruWFDln75YkP7 Eys8lowzpCOFtPOes5pJyn6heFJVw9/eYNLq6HH9JJ2EOIVyBwiJJMgjTQzQLQnKvDzk uAsnlFGITXqT3xgGaa/C+b+xY55cXL2SsoYDOkdJb3SywFM6pFoRdkb6bDlZEyijEce5 EyKjH4uBvSx2kAPnZ/oZgPR9V6fFvg10rxFxRo1P9M8r7m2dsvrsN6LSZtAIPoe8rOz9 VVAIysYKVbui5H+cArGffMIwU/pNkYCzpkGM1Th40nkBctTuH6x6ZlmaPFyncQY9be0/ ebXQ== X-Gm-Message-State: AOJu0YzE3tYTyV3455DerKUCoNDE1HwnzCRaf592e6z2uxB4L0wy71Bx XAT6tRrTk2u/c0wbIeiqBSaDbX0Z+zY84nN3Ikt2bd0AkM0o72NvoUvU X-Gm-Gg: ATEYQzxjmeq2aVjsTQ/iT8gwDDWVJFobHjInM/Qak6QRKtKXe3Dp84CyUSosU/9Pcrt 4EUggflAREE2HXs6UCEQzM63zVPaERscje3BrmvNKSlf2VRNN4qDcCrxwb5AZxFOc1GQ6oP3rzM fBVAtH6Z0ILyvEgYpZcuv3H0htGD2GVpdXMWE4VimskHQ10hMqklrxW2plbhYfnZa4WhjgqW40c BjcLdIGiTJ8gLGvUx5yTY9Di1EEHtSA45fLjqQyNf1KuW4/bdk8OdaIDgKhe7vby2fbxBYsU3Nk JbNnr9fZpQPAImiam22DRsf/nL9KpHtALlHKL6/3bLzp41jCTwAPEMppoPTurtIMvmd8mmnNK9m jIis3ndVbw6AruYvmSVBWqcJAZj2fkMI6Po3AvFmcueztlEfcINYhKfe60GpeTw/9d+MJOs72jo GVo24GF7qYi5QWp90pcInOlgcCZ2xdNTApOl0rUiskuflOlQ3N X-Received: by 2002:a05:6000:2089:b0:43b:5356:a7fc with SMTP id ffacd0b85a97d-43b6428b374mr1147641f8f.55.1773951968561; Thu, 19 Mar 2026 13:26:08 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.07 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:08 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 49/55] drivers: hv: dxgkrnl: Fix build breaks when switching to 6.6 kernel due to hv_driver remove callback change. Date: Thu, 19 Mar 2026 20:25:03 +0000 Message-ID: <20260319202509.63802-50-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov The hv_driver remove callback has been updated to return void instead of in= t. 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 retur= ned" Signed-off-by: Iouri Tarassov --- 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; } =20 -static int dxg_remove_vmbus(struct hv_device *hdev) +static void dxg_remove_vmbus(struct hv_device *hdev) { - int ret =3D 0; struct dxgvgpuchannel *vgpu_channel; struct dxgglobal *dxgglobal =3D dxggbl(); =20 @@ -830,12 +829,9 @@ static int dxg_remove_vmbus(struct hv_device *hdev) } else { /* Unknown device type */ DXG_ERR("Unknown device type"); - ret =3D -ENODEV; } =20 mutex_unlock(&dxgglobal->device_mutex); - - return ret; } =20 MODULE_DEVICE_TABLE(vmbus, dxg_vmbus_id_table); From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5CBE2402BB2 for ; Thu, 19 Mar 2026 20:26:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951973; cv=none; b=bfUxt1+D38mstlxhkA5UthFGLZ8IgGv3NX2GAogvv5cv87+Z4qsii+QvuXYmu6VogBim/knMnX5CIW4m3yqM9+R9Qgf5/SBF/2yJv8dZRRC/fPVmHbFc+m6FahnfzMLpCXMImSnu5MmlwYdvxpsPj4vemHvc1LsT5dQFcTIjYSI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951973; c=relaxed/simple; bh=CYzAd6S2tuDyMt904iUrjc5QlAl/T5Oy/hTKXGVuzUA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mHBM4t6ipmb18QZQjw0Mav7oWbMjt1P18dPK/22ZuA902LUyzZaavJYJpfHU8lVnIGrLmqbSHyE1TUHO9NwG+0aDtr7x5c+DyQ/1tkc4djCjyiBwz9MK/4k6TBSQpXpx7VrA2LefkValyeL9SaPP7OdYvPc37VJENavJQViuCDQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CT91zqyN; arc=none smtp.client-ip=209.85.221.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CT91zqyN" Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-43b49819938so713115f8f.0 for ; Thu, 19 Mar 2026 13:26:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951970; x=1774556770; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8T94hCUBCgJxRtV1K3dOdspjWMVTTyxiqKQc25Q0XT4=; b=CT91zqyN+dvLLJVIzAYSXQRh+f9gqVxqHrzBoio7Sz8GXzlZZXUpBv5IJnxGrJerhI 4tuv0wrW5LR+JfjTHAFYAkvpEOzsqlPfUSk0W8Lf0GoxoGxvWBKewkcDkSuOyiRG7YvL Y1/+v7+ZrM02ZKp0VzSfkec519gJgMZdCviDBfg4M7jgMWZ8FrkCf7ft/SgOHoVsYQNM broSmvavT/A0FC8LLkKV77yTCoU+8e9xx7apHrnaYV5aiDOFl1YeHd7rxCCXT5qYTExY 1geUP050xKB3CR11DLFFNtelr+ZTAC3gJ7uQfQRSzD/h80PbymvKRLOchIGKhVlSwGaG 1Udw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951970; x=1774556770; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8T94hCUBCgJxRtV1K3dOdspjWMVTTyxiqKQc25Q0XT4=; b=lLVqxhH7dZ56Bt/RrOa9d4WAU7b59kYbGUNT2aqDtuCka3zV5dynJKFwrRlUUdiNyK 2tBRWuilRmIsraXaLV04wkKYNGIqeWFCDKoAg+ZTUyKcGtVzRAoXq/2x4nsWjzOHPH4D ZRaTYcOnlg4mLGb7ylcbzW4qL7HsDnWdQJd7BEqDi0HPuVFeujjuAnBbFaAWHHXnLx4g 1WAm4q/B+S1qOdwPBCmdUmU0sbQ02obT0QwQ9cIVZPYtQoK/jAHf8uWyW7AK+Rw4YTNo pj+6D4b3wVCHxFyzlrCaa3W7bx/KOpjskQmme43YzhMUaYHff7IgLPq2uxt+W3v0uWEP QVQw== X-Gm-Message-State: AOJu0Yz77UKYNwfSxqYkI64sq/cp9nYDqo3RVgO1XLIv+82kP6d5RMsV 64NrnPni3WucQ7c0tVKGndhoAQBY1bu7ZS9i9rf1uiH+EmfLz3axd+S8 X-Gm-Gg: ATEYQzwB1CRdbWDEhRHzMdxjoSNknhsHpbg9zqUADpdUsAfX0TjgNiJKfDNzDiohFQu AZy83kPwnL0CE6YQSfCcHt6Abv5iFF9mg7gOx2+gwI86p7azLtgrydVeiece2fVVGU6QBXAKA91 bgkWDKHPfKv3mXu8fjm/3v8AhiwTECag5PHH0SqIXiaw1PXPpZ6Tg4agIOH/v09xILyimsbhoz8 5dooULoGR3lN73HhKKji6mfL6Yef8vEy//+8dXi4jZoQQ9M+Coo++kfUwhepXnmU6g1VghfiWkg XZeFVUeu8YEFRG6rz1K8ggigsjpVG3p5VqQD3FLaN1UZCWJGc/fZQX4+b3sfgeVfUz78lkaqCcx /VWjMZJCAqYpG15Iu76t+1SoEoXrHnj2zTB2sGMeFW3gjnbvyMGSCx2BoXwkkfCj0J1lBN6+bGU wzc9KugRB5UIs5kc98gEfaK4/s7Pdanx15YrR8EerKdBsL8W0p X-Received: by 2002:a05:6000:2203:b0:43b:46b6:87aa with SMTP id ffacd0b85a97d-43b64277e1amr1210039f8f.27.1773951969551; Thu, 19 Mar 2026 13:26:09 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.08 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:09 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 50/55] drivers: hv: dxgkrnl: Fix build breaks when switching to 6.6 kernel due to removed uuid_le_cmp Date: Thu, 19 Mar 2026 20:25:04 +0000 Message-ID: <20260319202509.63802-51-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 --- 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, =20 mutex_lock(&dxgglobal->device_mutex); =20 - if (uuid_le_cmp(hdev->dev_type, dxg_vmbus_id_table[0].guid) =3D=3D 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) =3D=3D 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) =20 mutex_lock(&dxgglobal->device_mutex); =20 - if (uuid_le_cmp(hdev->dev_type, dxg_vmbus_id_table[0].guid) =3D=3D 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) =3D=3D 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 { From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5E8AD402437 for ; Thu, 19 Mar 2026 20:26:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951974; cv=none; b=GQNBgiBr6kgIDrSdcJuHsgzNSj96E65Rs6uhIhksyolGO61f00NICVQ4QPXvFoLtnipQbxzyR4yi+siAqcUO8Acn10CJhA33aRFT1lEezB8Dkte4j9KLDXh98kFUyKolWLf2WB85+eHFLi3NranmQNU1LCLH8az6xYiO4S3yqic= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951974; c=relaxed/simple; bh=outTnRIBQAyg28okb66wf80x45Mq14FYSPhGHqeYDkw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bCVdMMKlSIkT2kInR/TupEBqTh6D7LCmiFj5TPc+qD6wu4ZIOboYAdJSbiFc7UcSsF43iywBtSnqhtIlRccBkCg4k7Waux09Kws4pGwhYftv5QCsXv1h35omadNvrb9jNmhDHa64/n2bMQyBhc8hipovb94wP55ezcnzwZ0eoLE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=RcgHMAuy; arc=none smtp.client-ip=209.85.221.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RcgHMAuy" Received: by mail-wr1-f51.google.com with SMTP id ffacd0b85a97d-43b4d734678so1373484f8f.1 for ; Thu, 19 Mar 2026 13:26:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951971; x=1774556771; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XZHA0FJqnrMUZiDF+/x51qEC2Ygiwx2MeXeyqpq00vs=; b=RcgHMAuyJ8YvIZIq+2P28HVdGFD6nmf2vvZ5VMckttp9d38qdL6LB8t+UVJc5kYSS3 CTaX6ph9Po40Kou7I4kEEN7DeDjEclynwT3wgQ6LZD9pUGuoa9H8jJq8re2v7nDxEby6 pBsXdg14a1kaut+xfe8xiVHW7DFaiUOwhusg0D/vkqPZPve8oX+EmH1oPDjngo527RlM YLfEW2eemq7fqGmBMmdcPULngCrKhmvAQGltpMwoRDmQqrw4W3YLVvA6rx+mrP9/HUa5 eF5KHeUacMz9wphgA0zqI8YUjWGFFs9LLsAW5vPuZvZIQi37DPoD16vB0R7k3gOiK+Ym JHlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951971; x=1774556771; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=XZHA0FJqnrMUZiDF+/x51qEC2Ygiwx2MeXeyqpq00vs=; b=aZGQI2mfl58Jt5vhlBNwgQNMtYjdCvm7y3bUTp3YWJN+kM2+Ei4AdtJV3EVg1l4Hub WrdPtW60nS4JJcWiv8NCKT75iXHnn/yIutLQ79aEFfp3VuIxzrn346efFopCmsLAWwe/ oYHj+rde430GR3kUHOqTNeKTJYDrvmkq6Qk+L+ZY3rVEZu76NBTGh7ZBnYCI2uU5AIUN 8tfedpAGX63RXDRDYP+Hg94h08JZrv8PXh74G6ris/qd9T6XRdmUd5S80IOQAxk4+xGb ExFbTSCOCqB+GAqe4bMntQF5qlWcQI2aiN36MLtugT97t9n2NLeM3WQn4w++Ydi+SbFt RJBg== X-Gm-Message-State: AOJu0YwzjuoKF5Zi5Qpj1IpBaByMpzvgurThel46w0TphLc40cKU/ZTd 3By9ES3CGCUma8jK2c+UW/qkUa7FJbRTR/Jd5iZP0fzRpFVNw24CjLPh X-Gm-Gg: ATEYQzxdYWVzDc4Y3ZKiXDBmfpJ4FIw6DDviOfdJVosAgpiOSIhb+G1ceGHB4qd+wAS j7qSJKVwYr7tOM0Xum/cAKwrJ9t3+US3MrpELPZOvWVllvO5ASMDKw/r7HCZSSO9Q/GV8iYuq4J 4kcd2D/jr+xxSLOietxpdE+eO/aM6n3BLWm8MIdcjiIbpOO8oOjj10Aqma2YuKPezyH2U1nHHiI BlH4e/gtdjs/y5xtZECh7ymebBSwN9NReeQ8mrhB2YuGUB3ILrvLZAxj4rZ+I1kjV4O50G+k2CA 0p9shSX0ljzy2nWiXXD4Vvl6x7obnOprpeaGEX60og87gUHMwCjy9mZsC5Vr+dg9gA0Amw9PLXN 26HUoN1BDRQH7vz51KpPk7EhHXi7A1GK8vWV3DFoQM/kNe69nJAbyRK06eambACHDMP9/PQ/0Kq H7KTkhsMZ1clHVCEAeKiddbLOo48pOG4gYaXFGbkJjHNKh6VMc X-Received: by 2002:a05:6000:24c4:b0:43b:45d1:f449 with SMTP id ffacd0b85a97d-43b6427cde9mr1224789f8f.51.1773951970522; Thu, 19 Mar 2026 13:26:10 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.09 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:10 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 51/55] drivers: hv: dxgkrnl: Implement D3DKMTEnumProcesses to match the Windows implementation Date: Thu, 19 Mar 2026 20:25:05 +0000 Message-ID: <20260319202509.63802-52-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov The behavior of D3DKMTEnumProcesses on Windows is that when buffer_count is= 0 or input buffer is NULL, the number of active processes is returned. The Linux= implemenation is updated to match this. Signed-off-by: Iouri Tarassov --- drivers/hv/dxgkrnl/dxgmodule.c | 2 +- drivers/hv/dxgkrnl/ioctl.c | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index e3ac70df1b6f..8f5d6db256a3 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -965,4 +965,4 @@ module_exit(dxg_drv_exit); =20 MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Microsoft Dxgkrnl virtual compute device Driver"); -MODULE_VERSION("2.0.2"); +MODULE_VERSION("2.0.3"); diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index f8f116a7f87f..42f3de31a63c 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -5373,7 +5373,7 @@ dxgkio_enum_processes(struct dxgprocess *process, voi= d *__user inargs) struct dxgprocess_adapter *pentry; int nump =3D 0; /* Current number of processes*/ struct ntstatus status; - int ret; + int ret, ret1; =20 ret =3D copy_from_user(&args, inargs, sizeof(args)); if (ret) { @@ -5382,12 +5382,6 @@ dxgkio_enum_processes(struct dxgprocess *process, vo= id *__user inargs) goto cleanup; } =20 - if (args.buffer_count =3D=3D 0) { - DXG_ERR("Invalid buffer count"); - ret =3D -EINVAL; - goto cleanup; - } - dxgglobal_acquire_adapter_list_lock(DXGLOCK_SHARED); dxgglobal_acquire_process_adapter_lock(); =20 @@ -5405,6 +5399,19 @@ dxgkio_enum_processes(struct dxgprocess *process, vo= id *__user inargs) goto cleanup_locks; } =20 + list_for_each_entry(pentry, &adapter->adapter_process_list_head, + adapter_process_list_entry) { + if (pentry->process->nspid =3D=3D task_active_pid_ns(current)) + nump++; + } + + if (nump > args.buffer_count || args.buffer =3D=3D NULL) { + status.v =3D STATUS_BUFFER_TOO_SMALL; + ret =3D ntstatus2int(status); + goto cleanup_locks; + } + + nump =3D 0; list_for_each_entry(pentry, &adapter->adapter_process_list_head, adapter_process_list_entry) { if (pentry->process->nspid !=3D task_active_pid_ns(current)) @@ -5429,10 +5436,10 @@ dxgkio_enum_processes(struct dxgprocess *process, v= oid *__user inargs) dxgglobal_release_process_adapter_lock(); dxgglobal_release_adapter_list_lock(DXGLOCK_SHARED); =20 - if (ret =3D=3D 0) { - ret =3D copy_to_user(&input->buffer_count, &nump, sizeof(u32)); - if (ret) - DXG_ERR("failed to copy buffer count to user"); + ret1 =3D copy_to_user(&input->buffer_count, &nump, sizeof(u32)); + if (ret1) { + DXG_ERR("failed to copy buffer count to user"); + ret =3D -EFAULT; } =20 cleanup: From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f48.google.com (mail-wr1-f48.google.com [209.85.221.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 45B604035DC for ; Thu, 19 Mar 2026 20:26:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951975; cv=none; b=nbkn38o+YMnscS4oluK52wQdO7KHsXZijPgCpYqFml6gsnDDpPsIOSfjji0l2/Yh/0zWbDIBVmNLcQM6NKhODM0qH2URz7HbTpPH5HXedcWom5fc2ldGkgpG5RHDaKE7NNrHv6kkOBvZGkxe6hSHCfbZUZmnZvZbMdn4iKmG49Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951975; c=relaxed/simple; bh=AOusT6p9367uyjTqPMakWydFQ1xoyk/26t5GlU5mVyc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aBv9Byt/Tv6H6StXKGQuMlC03+giiLPKImEe2yaMTMD1bpxptt/BAxWFtHb0Bsq+B+PYc6+dL/pLFMQRWGw0iNZ/9ZGMGv/zOq9KOZbhGpbHgDPWems2p1ZNKqJHRsmQqEcb7ztHXxwQgoiOektvLgX46Rm0fIMqORpO3NvnuS8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=a4ryd15C; arc=none smtp.client-ip=209.85.221.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="a4ryd15C" Received: by mail-wr1-f48.google.com with SMTP id ffacd0b85a97d-43b45bb7548so900782f8f.1 for ; Thu, 19 Mar 2026 13:26:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951972; x=1774556772; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=5nBvPxHuGTYxL2H7tm9LrajSUYE8m0XRxOYwCtqlQeY=; b=a4ryd15CxIsWb50OPCdRTFv+Doj0P+umdHRv+qN3FVSK+7o5OqA05ob6fACtCRinl9 uyqc08p8fCb2lHX7IWQXnpu+KvCRWq0krMsV/y7O/5D+3hk5gSm1z+sSe6KmbH2RHPJF V7Ypoicpftnt1JW7iwoaD3CaoFVxH5bSa6toSw/CZBBQ3nlyC2g9+Qi6eybEO4Mv4JEy hYjUE0XcW2omT5raCk1cANJSZRz5RU4CTT+n4uljBp9FdQGd3DBeFR4psxSYqLKnJClp Nv3LxTisGO2APLrhGjhZPnVlHv1taSasu7uoWF1ONz8q6IxdPgiB8UqLVEPzXlxzKGUu +W/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951972; x=1774556772; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=5nBvPxHuGTYxL2H7tm9LrajSUYE8m0XRxOYwCtqlQeY=; b=PVfSAqdvBmhl100F7vGMXMYsGLdhLScTq8lR6QdviKVAe0sEemg/0HZHbvtRQsTK4h As185v0qr1WNIC7IxcQ969mnqf2QlImeGf37+UQHm7f7PDaBub35uaPV5H4KSMjjb6rp Lra+Y2tsW7VazP+8hGcS7CoqUoF9JJSE+9Xwj6qeUNSesxvkbZa1CyfkALD1eAiIJIi4 IISeMvy1Yna1NWNuAe1/SizYrWGkDACqzvTGj0fP9ScSHkarSuQThaHkHFuawz9dr9Uh BaAvoWIfLnI9/6MPNXU6Oo0y7F0ca/7N/qiUlEMmvrV1uNxZLiGL//5c8kjhrPvz6jx+ bWPg== X-Gm-Message-State: AOJu0Yw+DrweHFCBGiaWaI57L6WKAPHIGd/JzQsYChZtj8rpsjRaPPjN WnS+Hl2zWix4BbggxKnHRHzCFRd3mLUZPFqBdXbYKvo3xGIK8tcbyOD1 X-Gm-Gg: ATEYQzyoUSUqXXA3JmC+Lx5wutXo31qXQAqjYpqMU5qaW4rMbPAoyx/xfW3xOxFS/g9 9CfYK7/XaEaFSHTUyJOC+OPH9hGQFc+CXLfYaO/4fycKfIc/bmBPL1VqAtElUfz8XBjUp+zXM/I 0EQjOOXde5jO3HUDYz3OIRy5d36svluV1aboD/6tyEgzB3ozzjKWtMQueDYOhba5uR4kAbQrDRh 6kaf4ssqzRAUlAPL430YGecmzGfh8w/XEvibTG6QqQKDGm/TEUt8YiEXA6DBOHfbo9PcLgOQUiS 3+Y1gbrdAO56ODY8lCoc3X3uURtb326PEmYJWiQvrclCIZ26n8babKEzFVLe8xDY12/KB/LvOsR yt76Y0VrxGv+eEipKQXI5VnjkgAdb9JVaBLzuYgbAr33GF+1Z5E56bczGgNmVssR8g9dah1Ho/j RGNE4ZXU+KOBsDq5zr2wVYR8UsMTTFBhT0kEOotcm4nnpLWHwi X-Received: by 2002:a05:6000:2f84:b0:43b:40ef:5d1a with SMTP id ffacd0b85a97d-43b64240089mr1066767f8f.5.1773951971528; Thu, 19 Mar 2026 13:26:11 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.10 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:11 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 52/55] drivers: hv: dxgkrnl: Use pin_user_pages instead of get_user_pages for DMA accessible memory Date: Thu, 19 Mar 2026 20:25:06 +0000 Message-ID: <20260319202509.63802-53-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Pages, which are obtained by calling get_user_pages(), can be evicted from = memory. pin_user_pages() should be used for memory, which is accessed by DMA. Signed-off-by: Iouri Tarassov --- drivers/hv/dxgkrnl/dxgadapter.c | 2 +- drivers/hv/dxgkrnl/dxgvmbus.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index cf946e476411..c94283b09fa1 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -882,7 +882,7 @@ struct dxgallocation *dxgallocation_create(struct dxgpr= ocess *process) void dxgallocation_stop(struct dxgallocation *alloc) { if (alloc->pages) { - release_pages(alloc->pages, alloc->num_pages); + unpin_user_pages(alloc->pages, alloc->num_pages); vfree(alloc->pages); alloc->pages =3D NULL; } diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 467e7707c8c7..abb6d2af89ac 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1457,6 +1457,7 @@ int create_existing_sysmem(struct dxgdevice *device, u64 *pfn; u32 pages_to_send; u32 i; + u32 gup_flags =3D FOLL_LONGTERM; struct dxgglobal *dxgglobal =3D dxggbl(); =20 /* @@ -1475,12 +1476,15 @@ int create_existing_sysmem(struct dxgdevice *device, ret =3D -ENOMEM; goto cleanup; } - ret1 =3D get_user_pages_fast((unsigned long)sysmem, npages, !read_only, - dxgalloc->pages); + if (!read_only) + gup_flags |=3D FOLL_WRITE; + ret1 =3D pin_user_pages_fast((unsigned long)sysmem, npages, gup_flags, + dxgalloc->pages); if (ret1 !=3D npages) { DXG_ERR("get_user_pages_fast failed: %d", ret1); - if (ret1 > 0 && ret1 < npages) - release_pages(dxgalloc->pages, ret1); + if (ret1 > 0 && ret1 < npages) { + unpin_user_pages(dxgalloc->pages, ret1); + } vfree(dxgalloc->pages); dxgalloc->pages =3D NULL; ret =3D -ENOMEM; From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70311405AD4 for ; Thu, 19 Mar 2026 20:26:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951977; cv=none; b=KPen503mxYaapEVSFqGPL/WzmCJ9MGnl8XSIgY2EnGZkKBGEWHlm8TmUX8zi3+uWamzzwlrHoo1VgcZjPnKXrD8XUmMQThyD7OvD1G9d/0UpkgMsiyc1uvBBl7gSAvkbVcDupSuL2Dp7cgDZNc2qqeZm9XfgfVmBMPecjNwEUHo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951977; c=relaxed/simple; bh=RXAKopPqswssMamyZTu+CjsystEpYm23+bEkJx/MHsI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pIfhY/e9O7S9XbUKfR5EwCbj7qa2yRI7DFJOqJ3UvjbMYXRc2g9nyMGlA1CGvKmhcNYC+txA3WWx02UjwQKi36LlLrPvJY+C4o2zptr0Xf7j/oFsBZaC857+fkyHa8o29i5hXpMZctbEd94xcW5yXVfPTcRRXO9UJbhvL2+A4sw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GLmUfEl5; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GLmUfEl5" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-43b4d734678so1373515f8f.1 for ; Thu, 19 Mar 2026 13:26:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951973; x=1774556773; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=M4Vjw28unlG5YFFVDdPo2EpwlOdhnBXqMUOBR/+aRX8=; b=GLmUfEl5ZOQ5OmLilT5g++YYTXVwY+1G1fWh1b+3/oQrJ/NfII4uWETBFgbR73+uUq 3kRegHl1f4G552JQxOM7S3eDSOjc753b8oPSgoWwIxt4cCN6xjjOP/A9JMQGG/5a0uGP EhCyiHNOPx3xO9zTwFcWLJU2jycLUcAiqMprIgwRqujsmJKPLt9C9idxWsrZz9gkOFDh EX2KWHoHeOwccx4xeeaLnNYoOClfyPtVo9pfMj91JzlVBT1o0GAx80pBS2k0MXUp3lKr UGY3SH+z/ex8JHtIYuZa5cybxI0Y2fJsNdLV+YBatU5tF8WLgf3ovp4cBg11FDnj3VgJ IhfA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951973; x=1774556773; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=M4Vjw28unlG5YFFVDdPo2EpwlOdhnBXqMUOBR/+aRX8=; b=lYCFun+FJ0JNeyRlmVonsURe2tZ/h4YKuRpk3dhBsty4rWCWbIv8ct6bUz1ChEPHNS m3hCb2THHpV7gPD6QT3OpQMwT1M1om0MMdgFrPsLPbr8h8cdRAf2M/BGzX0pCjmC8ayp yD3dSC6w4Rji0xsjNQTcLlKFOixxeLDbzYZdJHVtuVbBBXjGvgHIyYP+7px/URP+vaRE zM2624yyksCEvb1DRumF3S/bC9S1zzcyMj1rDbm7cRXA34LRakizTE5tcZWbGpcQfFkN tm7RtT+nl8CIm9hdnqFSK7oEn8DGQiijnZSa8qeSlgtYqoRTcCxYi2s/bEzfHo5qufUH e2kQ== X-Gm-Message-State: AOJu0Yzr8a6qYaMM9ofi1lWju7x0GU6yxEqrIwKoiN93QwnV/HdGB2wy +3VDOq4+HSWt3eNEVfCdwEYOf1w+/vQAzJG/lwc1a7mHXP4MEuT10GhY X-Gm-Gg: ATEYQzwj2+iaSQ5Y6wBVbm5j/goE0czqDv7ALFt5y68peZuFy86ghVGnJ1PSvvCc1PT T4FM0idjkyuOdOmQYmc/60Eh9TmNEnpWYzG+G9kXN7LmP9isPwEJ0KIJVgNFcfxlcu+BMEUX6ql R4xt8Y9o21O1K3ViBi12aCyPKlish7ZfIjU3Sam5M4z0Uf7cTn6k0YcztCGo5uOMoTN0OWVbYbN IxkYxXYXbm16k5lxoLbd6z48r08D+RctLFooOiNB2dZkmtxUm8jxb+A8vdYsMd1Hhysqsa//YC+ AN1QGeF88Sixg/UP9nxcfgtC7xxCsSsCz0FpS/AF8ybq82V+ZXZ+g3U3NYXawmagqpoKpXIoyCk vmfmswyOVh1qDFbBlwvEcrHW3+qcyVmB8MvgGFpOlMMErieukbjlLSdoiHlnvtsYT7i610X4CR/ B4IJXeJK70R+ISPXg++FystQeYdfDDlRCatcIxXAHMg5y/6RKk X-Received: by 2002:a05:6000:26c3:b0:43b:45d1:f438 with SMTP id ffacd0b85a97d-43b64234722mr1195366f8f.3.1773951972545; Thu, 19 Mar 2026 13:26:12 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.11 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:12 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 53/55] drivers: hv: dxgkrnl: Do not print error messages when virtual GPU is not present Date: Thu, 19 Mar 2026 20:25:07 +0000 Message-ID: <20260319202509.63802-54-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov Dxgkrnl prints the error message "Failed to acquire global channel lock" when a process tries to open the /dev/dxg device and there is no virtual GPU. This message should not be printed in this scenario. Signed-off-by: Iouri Tarassov --- drivers/hv/dxgkrnl/dxgadapter.c | 2 +- drivers/hv/dxgkrnl/dxgmodule.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index c94283b09fa1..6d3cabb24e6f 100644 --- a/drivers/hv/dxgkrnl/dxgadapter.c +++ b/drivers/hv/dxgkrnl/dxgadapter.c @@ -78,12 +78,12 @@ void dxgadapter_start(struct dxgadapter *adapter) =20 /* The global channel is initialized when the first adapter starts */ if (!dxgglobal->global_channel_initialized) { + dxgglobal->global_channel_initialized =3D true; ret =3D dxgglobal_init_global_channel(); if (ret) { dxgglobal_destroy_global_channel(); return; } - dxgglobal->global_channel_initialized =3D true; } =20 /* Initialize vGPU vm bus channel */ diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 8f5d6db256a3..c2a4a2a2136f 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -46,9 +46,13 @@ int dxgglobal_acquire_channel_lock(void) { struct dxgglobal *dxgglobal =3D dxggbl(); =20 + if (!dxgglobal->global_channel_initialized) + return -ENODEV; + down_read(&dxgglobal->channel_lock); if (dxgglobal->channel.channel =3D=3D NULL) { DXG_ERR("Failed to acquire global channel lock"); + up_read(&dxgglobal->channel_lock); return -ENODEV; } else { return 0; From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f53.google.com (mail-wr1-f53.google.com [209.85.221.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 715D4406283 for ; Thu, 19 Mar 2026 20:26:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951977; cv=none; b=gp/p8SJmuC5R7Fp7B/6yRDtNtCa4i3Y23w/c0kzbpnDawMxJ62tGhrXnm4YDbLKyjKvoHQeX2SN/u8UG/dMHjIJSwqADB9DqWaI6PoRVRQVxeG2mXa29woCQowRcpH/NIapKQ+9NIvzkfRirGW+N1SW/gCvVa3ncEU012kxh3/w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951977; c=relaxed/simple; bh=64Yjo7ZvmJXvIMfS8hCbiomKgwsOGgRqkHQNG224eB0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fwxqcCQ3OiIjs9VuWti1AtxzhhN3vQ/u5kShjLprgZFhhPHBGH52bK+qlJRKKEbWF+iarqGKm8Pzqbi7QEJN5XZXVl/CxI5iDjZPlSkngC+Eo8qRPZcjMwN4qZNuMUi+mT/VVYEynDS6/uRr0yhSuhtN339c9Tg/Se5YU7jW1J0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jk7dGGM0; arc=none smtp.client-ip=209.85.221.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jk7dGGM0" Received: by mail-wr1-f53.google.com with SMTP id ffacd0b85a97d-43b4d73463dso946612f8f.3 for ; Thu, 19 Mar 2026 13:26:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951974; x=1774556774; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sq7pLRQgbUoZPtACF262weOXRDH8/ti4RFZhN9vDeZQ=; b=jk7dGGM0o+auPryu6y4fotHKDslBd69DwCXT4qoksDq1zB75d0QIQUN39b14jyjrrv 9OXoiblg5WDuyRDzlLWcB23M/qyJeKZDAbrsB0TsA9M94nbjAHPl7s63jezdrltQ1VNR 5p/C668x8w/9bJTRx27veww9HUMVpJ+DAahZ9XfaUeAW87fAnRaBSHRSSVtibnlJIcdm BcBSOuuIthTGSbccV8+f9ku9+tEg5fR8NOVSROopivfqjcm2efbyVkkEB8mFzTkGFRtp spaWfkkVSsfRAoFuf7j8PNb8dbKyJYmjXwBJNSS/p4V+LTr17fDInRuHw6ineZjCYNKl +dIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951974; x=1774556774; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=sq7pLRQgbUoZPtACF262weOXRDH8/ti4RFZhN9vDeZQ=; b=YZbnJp/Kr+snc34+EFtTWqXUxwXZKjsfeia599izo1md0kvrOJ609V9NNfVIOJEdVm rdAsEtE44aDc2PGQkHCj4bmxt4hrAk8dQK12UaEJnZdCPZa6/t3wNLUIDwbZOzOhgnq7 QmOZcSDiBR5DGaxrtPwWKvTArNK9QYHgt/irWZ3Zx7U6mbkWRgRtKDhn886ycnRL101p 2R1QW2MZFU20rDOs3vSjYfdiLCqu5II5wUZzAWsyzyx3dCoQEwdnZ9M+SWe9WVMJrihL vQTPkoDXPHO0SDZk/fLhllmqorYIe3xZkfOdsDkamID5di/mHeJCMg7TMdt0Icxai8VI q/og== X-Gm-Message-State: AOJu0YziK4b04gbtz6hhjYaSFSkkLrSidk34XhfADzmzbFSAEN/7wOMR OOyMKpdnpn81yQva9IT/Wxe80taj/SFL4tUj5jnPH0tIc/n2avZkHnEP X-Gm-Gg: ATEYQzzTljXsN0N2KiET+g65E/4DbBYhkGbjArK7+Jwox9rIkPK3rqwWhaObhoD8urX vTJBDhz5KRVXv8YGxwJRVdFC/0rZEjz+S9QpWeC4cLXcHlOTsZb/lT9j8NhwHrsfGSRCD5IkAu6 7yeY3iHMaGBVmz48+CU7q4MUybeFz3GWxPFYDGEUVg0lUvSCrgycGUs8Va3jDtZNKKVrcwdgvcy ZAr3RqelbDNHtfkDaNLrWnntOYShjTMCO6Pp0k8jn02WEtkuoa03CaC6cLG4YexAEyTDehK8jSU ZjSged7rXe8kmbgrpmks7kQCIqvW8zsKihYNXX7pzAi47kHVH9CDVDklbAedM3R3tHehduSiRzI 3xZ5K921wb/TQTQkw6Hza9cx0k0alQaXlgWcOlN15s7ELYqrEBNmspkVMAINbolV45tCPC40auZ DJtAj7OBVW/u7nf5QNuObtskmIS4jUiY28lRx+CZs7wFTsFIZA X-Received: by 2002:a05:6000:310b:b0:439:f605:afde with SMTP id ffacd0b85a97d-43b6428ae11mr1251408f8f.51.1773951973717; Thu, 19 Mar 2026 13:26:13 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.12 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:13 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 54/55] drivers: hv: dxgkrnl: Fix crash at hmgrtable_free_handle Date: Thu, 19 Mar 2026 20:25:08 +0000 Message-ID: <20260319202509.63802-55-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Hideyuki Nagase Fix a potential NULL pointer crash in hmgrtable_free_handle() when free_handle_list_tail is HMGRTABLE_INVALID_INDEX. Guard the entry dereference with a bounds check before writing the next_free_index. Signed-off-by: Hideyuki Nagase --- drivers/hv/dxgkrnl/hmgr.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/hv/dxgkrnl/hmgr.c b/drivers/hv/dxgkrnl/hmgr.c index 24101d0091ab..059f94307a0e 100644 --- a/drivers/hv/dxgkrnl/hmgr.c +++ b/drivers/hv/dxgkrnl/hmgr.c @@ -462,9 +462,14 @@ void hmgrtable_free_handle(struct hmgrtable *table, en= um hmgrentry_type t, */ entry->next_free_index =3D HMGRTABLE_INVALID_INDEX; entry->prev_free_index =3D table->free_handle_list_tail; - entry =3D &table->entry_table[table->free_handle_list_tail]; - entry->next_free_index =3D i; + if (table->free_handle_list_tail !=3D HMGRTABLE_INVALID_INDEX) { + entry =3D &table->entry_table[table->free_handle_list_tail]; + entry->next_free_index =3D i; + } table->free_handle_list_tail =3D i; + if (table->free_handle_list_head =3D=3D HMGRTABLE_INVALID_INDEX) { + table->free_handle_list_head =3D i; + } } else { DXG_ERR("Invalid handle to free: %d %x", i, h.v); } From nobody Mon Apr 6 09:09:41 2026 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 977434070F0 for ; Thu, 19 Mar 2026 20:26:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951980; cv=none; b=Rr6XrZKPYVobYRnRJD/qK0LpTKURDg1juitURqnGIWqzZgZGbU/dVGp+Fp4TWohme5e2djVlCZCKvdYT5kRzmJK0tqEEPIFgRreUwkWKzVd9Bb7b9bYmOisOp0YfAyw58eF/RrAp9r0pdC4a6wPO/X9RNZawJ1Sbw2IiRc5R9XQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951980; c=relaxed/simple; bh=ql0Xd4LG9x6eDqclJsYGXJsH5ZH2WHcszH6YkEhQ8A8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WGST3UD+rGcf9D7xj4xhFes1T2GnGqS4KtWf2HOkD8UTYvS4Xgv+PIU9W97TtyfvlgW9V4eiWB51FSX5FzK1bbIfevLKCiG9cnRwg7G2s9mL19+6jZGlLEVWsxw6+7Q0+fWgN7IDsWuVDc3LfjKoe3W0him5pAFwwjNzsG11P6E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CqjJjoed; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CqjJjoed" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-43b3f91a7abso760023f8f.1 for ; Thu, 19 Mar 2026 13:26:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951975; x=1774556775; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=s5uGyQLEbHu5J/MxRZx0GZsIsi9tax5qP4TW0jWXf40=; b=CqjJjoedq/tlNTU5eWf/1rnHyYdEV2MS5+LEOEyHa1gahFhpAWngLgk6+W6ZKrZHGp QvJf3YjtTXiPHjY1NvU2vmO5f3QhZCfJQ/yTTC07A8NqsG/droSfVzvIlVkGNi4aQ6Z7 qO2H53R8MHPAoqxwnKedYsovQipOGnzmFzykw6xMJxJO5kPAW8eqk97uAis2/SGDAhS7 i81j1YwqkTewQqZS0cQHBxruvvSxp5TGpuUTYb5MneGm5dUZ+6MTezLYO2SiiJs7QSJB Caf5sJYFqifRHMMw+Mo8fRV2FjvAyimuFKnEO/DY4lzHt+GyJUYMI9PfxXmCIQD6NhTm pWhw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951975; x=1774556775; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=s5uGyQLEbHu5J/MxRZx0GZsIsi9tax5qP4TW0jWXf40=; b=SbvCY2X06ltG/he70hexU5cHa2ZPQrUSkFyszsDLjMMiquHK7wgilpzZ6jlRCKOrvR Ho4hCC+hksbXu6b5vUC+7uEwa4vHzrXlL9P+r7dZeZhhzzOXuX1Ydlc0Srz+b86PxGJi LbESkytTi+EbHK4W4BT0I6In4dGZazmHOpLUOMqtNz34igIuPwC0d7Lx0eVX+6xjwAGo 1o54LDnAG0M+M7gVKJdw80mBFByCYJK/cEL7rBcNs7+RmwWHeELZzhTn7z3YwC8uTHXh oK/162jC8I0RApizLdJ32UAXNPf2ckVRoOtLAXIKkytJnd37DpLZQf9cL9nvp3Z8z3/E m9NA== X-Gm-Message-State: AOJu0Ywmo8QDF5H+UO4BKNSn2AjmNg3Q794gwJ++PPynPb7NA0WQ52XS mGTge37fwyEAAi7B3Vlkqqx6pswDyIK5Vrl/7qwljn5OpgZtc69/8FJH X-Gm-Gg: ATEYQzzKEfS6lEbhiCBVQHVkh2HjEAjJPC9KIhtrVAbQ6deHBrr4KAGe48LkqQ1p0NU pCO24RAzdjcBJ6YertbCUeS+7pYjWakqJ1lIuXQleu/XCB71sJneSGYGiarF6J/1dsbi11ZFUye T1dYEKfXMNzx2kmSh+RQ1eHnAssGvRanJfvqy4nyv6/o5NSRdeVYnTJFCsL/o0gzbDkiq14hwzn aB4gH2VHkJk/+m4OgB3wa1SKUrU1MEW8Y0dgy+5rXXGkQAGNKlkbXaMr8pmmQidMyUCmIjSMiVR uGcopJ63tK2dB0e7XJ8jDWvkwu0oUxDM9cFL5Gr/5D9bBIua/1xDUETBlmanMi2nXW07VvGtLgp rTn+VLnlhZulb7fUmB+xx2ryzYHWaY3dR026ZEDDgdY8Zz7oXaqr6q1+N/QOxrB6za2C/r4ko2A xM/wkh9rI8zhrrS4sI6qnTlEZQ4lE7/P/yDmLHtQNdrQ3wRXCw X-Received: by 2002:a05:6000:2383:b0:43b:445f:3177 with SMTP id ffacd0b85a97d-43b6427db29mr1239368f8f.31.1773951974718; Thu, 19 Mar 2026 13:26:14 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.26.13 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:26:14 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 55/55] drivers: hv: dxgkrnl: Code cleanup for upstream submission Date: Thu, 19 Mar 2026 20:25:09 +0000 Message-ID: <20260319202509.63802-56-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Address issues raised in previous LKML submission attempts (v1-v3): - Replace deprecated one-element arrays [1] with C99 flexible arrays [] in dxgvmbus.h and dxgkrnl.h - Replace %px with %p in DXG_TRACE calls (avoids exposing kernel layout) - Remove unnecessary braces from single-statement if blocks - Remove LINUX_VERSION_CODE guard: max_pkt_size exists in all supported ker= nels - Remove unused linux/version.h include from dxgkrnl.h - Fix whitespace (space before tab) in dxgvmbus.h and d3dkmthk.h - Replace DXG_ERR non-debug macro do{}while(0) with direct dev_err call - Change -EBADE to -ENODEV for global channel duplicate detection - Remove MODULE_VERSION as it is not recommended for in-tree drivers - Add explanatory comment to guid_to_luid() cast - Update MAINTAINERS email to iourit@linux.microsoft.com Signed-off-by: Iouri Tarassov --- MAINTAINERS | 2 +- drivers/hv/dxgkrnl/dxgadapter.c | 8 ++++---- drivers/hv/dxgkrnl/dxgkrnl.h | 13 +++++-------- drivers/hv/dxgkrnl/dxgmodule.c | 5 ++--- drivers/hv/dxgkrnl/dxgvmbus.c | 5 +---- drivers/hv/dxgkrnl/dxgvmbus.h | 26 +++++++++++++------------- drivers/hv/dxgkrnl/hmgr.c | 3 +-- include/uapi/misc/d3dkmthk.h | 2 +- 8 files changed, 28 insertions(+), 36 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 4fe0b3501931..493c65a02b80 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9772,7 +9772,7 @@ F: drivers/mtd/hyperbus/ F: include/linux/mtd/hyperbus.h =20 Hyper-V vGPU DRIVER -M: Iouri Tarassov +M: Iouri Tarassov L: linux-hyperv@vger.kernel.org S: Supported F: drivers/hv/dxgkrnl/ diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapte= r.c index 6d3cabb24e6f..d395fdcb63fa 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; =20 adapter =3D container_of(refcount, struct dxgadapter, adapter_kref); - DXG_TRACE("Destroying adapter: %px", adapter); + DXG_TRACE("Destroying adapter: %p", adapter); kfree(adapter); } =20 @@ -271,7 +271,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *a= dapter, kref_put(&device->device_kref, dxgdevice_release); device =3D NULL; } else { - DXG_TRACE("dxgdevice created: %px", device); + DXG_TRACE("dxgdevice created: %p", device); } } return device; @@ -720,7 +720,7 @@ void dxgdevice_release(struct kref *refcount) struct dxgdevice *device; =20 device =3D container_of(refcount, struct dxgdevice, device_kref); - DXG_TRACE("Destroying device: %px", device); + DXG_TRACE("Destroying device: %p", device); kref_put(&device->adapter->adapter_kref, dxgadapter_release); kfree(device); } @@ -1103,7 +1103,7 @@ int dxgprocess_adapter_add_device(struct dxgprocess *= process, =20 void dxgprocess_adapter_remove_device(struct dxgdevice *device) { - DXG_TRACE("Removing device: %px", device); + DXG_TRACE("Removing device: %p", device); mutex_lock(&device->adapter_info->device_list_mutex); if (device->device_list_entry.next) { list_del(&device->device_list_entry); diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index d816a875d5ab..4a4605f45736 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -27,7 +27,6 @@ #include #include #include -#include #include "misc.h" #include "hmgr.h" #include @@ -719,7 +718,7 @@ bool dxgresource_is_active(struct dxgresource *res); =20 struct privdata { u32 data_size; - u8 data[1]; + u8 data[]; }; =20 struct dxgallocation { @@ -769,9 +768,9 @@ long dxgk_unlocked_ioctl(struct file *f, unsigned int p= 1, unsigned long p2); =20 int dxg_unmap_iospace(void *va, u32 size); /* - * The convention is that VNBus instance id is a GUID, but the host sets - * the lower part of the value to the host adapter LUID. The function - * provides the necessary conversion. + * The convention is that VMBus instance id is a GUID, but the host sets + * the lower part of the value to the host adapter LUID. The cast reads + * the first sizeof(winluid) bytes of the GUID as a winluid value. */ static inline void guid_to_luid(guid_t *guid, struct winluid *luid) { @@ -1029,9 +1028,7 @@ void dxgk_validate_ioctls(void); #else =20 #define DXG_TRACE(...) -#define DXG_ERR(fmt, ...) do { \ - dev_err(DXGDEV, "%s: " fmt, __func__, ##__VA_ARGS__); \ -} while (0) +#define DXG_ERR(fmt, ...) dev_err(DXGDEV, "%s: " fmt, __func__, ##__VA_ARG= S__) =20 #endif /* DEBUG */ =20 diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index c2a4a2a2136f..435dc60511b8 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -158,7 +158,7 @@ static void dxg_signal_dma_fence(struct dxghostevent *e= venthdr) { struct dxgsyncpoint *event =3D (struct dxgsyncpoint *)eventhdr; =20 - DXG_TRACE("syncpoint: %px, fence: %lld", event, event->fence_value); + DXG_TRACE("syncpoint: %p, fence: %lld", event, event->fence_value); event->fence_value++; list_del(&eventhdr->host_event_list_entry); dma_fence_signal(&event->base); @@ -788,7 +788,7 @@ static int dxg_probe_vmbus(struct hv_device *hdev, if (dxgglobal->hdev) { /* This device should appear only once */ DXG_ERR("global channel already exists"); - ret =3D -EBADE; + ret =3D -ENODEV; goto error; } dxgglobal->hdev =3D hdev; @@ -969,4 +969,3 @@ module_exit(dxg_drv_exit); =20 MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Microsoft Dxgkrnl virtual compute device Driver"); -MODULE_VERSION("2.0.3"); diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index abb6d2af89ac..4b1ccaac440c 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -246,9 +246,7 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, st= ruct hv_device *hdev) goto cleanup; } =20 -#if KERNEL_VERSION(5, 15, 0) <=3D LINUX_VERSION_CODE hdev->channel->max_pkt_size =3D DXG_MAX_VM_BUS_PACKET_SIZE; -#endif ret =3D vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE, NULL, 0, dxgvmbuschannel_receive, ch); if (ret) { @@ -1482,9 +1480,8 @@ int create_existing_sysmem(struct dxgdevice *device, dxgalloc->pages); if (ret1 !=3D npages) { DXG_ERR("get_user_pages_fast failed: %d", ret1); - if (ret1 > 0 && ret1 < npages) { + if (ret1 > 0 && ret1 < npages) unpin_user_pages(dxgalloc->pages, ret1); - } vfree(dxgalloc->pages); dxgalloc->pages =3D NULL; ret =3D -ENOMEM; diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index a7e625b2f896..22246826d2f1 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -313,12 +313,12 @@ struct dxgkvmb_command_queryadapterinfo { struct dxgkvmb_command_vgpu_to_host hdr; enum kmtqueryadapterinfotype query_type; u32 private_data_size; - u8 private_data[1]; + u8 private_data[]; }; =20 struct dxgkvmb_command_queryadapterinfo_return { struct ntstatus status; - u8 private_data[1]; + u8 private_data[]; }; =20 /* Returns ntstatus */ @@ -391,7 +391,7 @@ struct dxgkvmb_command_makeresident { struct d3dkmthandle paging_queue; struct d3dddi_makeresident_flags flags; u32 alloc_count; - struct d3dkmthandle allocations[1]; + struct d3dkmthandle allocations[]; }; =20 struct dxgkvmb_command_makeresident_return { @@ -405,7 +405,7 @@ struct dxgkvmb_command_evict { struct d3dkmthandle device; struct d3dddi_evict_flags flags; u32 alloc_count; - struct d3dkmthandle allocations[1]; + struct d3dkmthandle allocations[]; }; =20 struct dxgkvmb_command_evict_return { @@ -476,7 +476,7 @@ struct dxgkvmb_command_updategpuvirtualaddress { struct d3dkmthandle fence_object; u32 num_operations; u32 flags; - struct d3dddi_updategpuvirtualaddress_operation operations[1]; + struct d3dddi_updategpuvirtualaddress_operation operations[]; }; =20 struct dxgkvmb_command_queryclockcalibration { @@ -627,7 +627,7 @@ struct dxgkvmb_command_destroyallocation { struct d3dkmthandle resource; u32 alloc_count; struct d3dddicb_destroyallocation2flags flags; - struct d3dkmthandle allocations[1]; + struct d3dkmthandle allocations[]; }; =20 struct dxgkvmb_command_createcontextvirtual { @@ -639,7 +639,7 @@ struct dxgkvmb_command_createcontextvirtual { struct d3dddi_createcontextflags flags; enum d3dkmt_clienthint client_hint; u32 priv_drv_data_size; - u8 priv_drv_data[1]; + u8 priv_drv_data[]; }; =20 /* The command returns ntstatus */ @@ -768,7 +768,7 @@ struct dxgkvmb_command_offerallocations { enum d3dkmt_offer_priority priority; struct d3dkmt_offer_flags flags; bool resources; - struct d3dkmthandle allocations[1]; + struct d3dkmthandle allocations[]; }; =20 struct dxgkvmb_command_reclaimallocations { @@ -778,13 +778,13 @@ struct dxgkvmb_command_reclaimallocations { u32 allocation_count; bool resources; bool write_results; - struct d3dkmthandle allocations[1]; + struct d3dkmthandle allocations[]; }; =20 struct dxgkvmb_command_reclaimallocations_return { u64 paging_fence_value; struct ntstatus status; - enum d3dddi_reclaim_result discarded[1]; + enum d3dddi_reclaim_result discarded[]; }; =20 /* Returns ntstatus */ @@ -804,7 +804,7 @@ struct dxgkvmb_command_createhwqueue { struct d3dkmthandle context; struct d3dddi_createhwqueueflags flags; u32 priv_drv_data_size; - char priv_drv_data[1]; + char priv_drv_data[]; }; =20 /* The command returns ntstatus */ @@ -833,7 +833,7 @@ struct dxgkvmb_command_escape { struct d3dddi_escapeflags flags; u32 priv_drv_data_size; struct d3dkmthandle context; - u8 priv_drv_data[1]; + u8 priv_drv_data[]; }; =20 struct dxgkvmb_command_queryvideomemoryinfo { @@ -879,7 +879,7 @@ struct dxgk_feature_desc { struct { u16 supported : 1; u16 virtualization_mode : 3; - u16 global : 1; + u16 global : 1; u16 driver_feature : 1; u16 internal : 1; u16 reserved : 9; diff --git a/drivers/hv/dxgkrnl/hmgr.c b/drivers/hv/dxgkrnl/hmgr.c index 059f94307a0e..95879f59133e 100644 --- a/drivers/hv/dxgkrnl/hmgr.c +++ b/drivers/hv/dxgkrnl/hmgr.c @@ -467,9 +467,8 @@ void hmgrtable_free_handle(struct hmgrtable *table, enu= m hmgrentry_type t, entry->next_free_index =3D i; } table->free_handle_list_tail =3D i; - if (table->free_handle_list_head =3D=3D HMGRTABLE_INVALID_INDEX) { + if (table->free_handle_list_head =3D=3D HMGRTABLE_INVALID_INDEX) table->free_handle_list_head =3D i; - } } else { DXG_ERR("Invalid handle to free: %d %x", i, h.v); } diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index db40e8ff40b0..a58b2513dfd3 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -1612,7 +1612,7 @@ struct d3dkmt_opensyncobjectfromsyncfile { }; =20 struct d3dkmt_enumprocesses { - struct winluid adapter_luid; + struct winluid adapter_luid; #ifdef __KERNEL__ __u32 *buffer; #else