Skip to contentSkip to conversation

Driver for Hyper-v virtual compute device

PATCH Superseded Iouri Tarassov 5 participants 40 messages Feb 5, 2022 – Feb 9, 2022

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover Driver for Hyper-v virtual compute device

This is a follow-up on the changes we sent a few weeks back[1]

[1] https://lore.kernel.org/lkml/[email protected]/

The changes since [1]:

- the driver code is split to more patches for easy reviewing
- static variable dxgglobaldev is removed
- various compiler warnings are fixed
- the patch for DXGSYNCFILE is removed. This patch requires more work and will be submitted separately.

Foreword
-------------------------------------------------------
The patches contain implementation of the Hyper-V vGPU / Compute hardware driver, which powers the Windows Subsystem for Linux (WSL) and will soon power the Windows Subsystem for Android (WSA).

This set of patches is rebuilt from ground up and organized in logical layers to better understand how the driver is built, making it easier for reviewers to understand and follow. The first patch introduces headers and driver initialization. The subsequent patches add additional functionality to the driver.

Per earlier feedback, the driver is now located under the Hyper-V node as it is not a classic Linux GPU (KMS/DRM) driver and really only make sense when running under a Windows host under Hyper-V. Although we refer to this driver as vGPU for shorthand, in reality this is a generic virtualization infrastructure for various class of compute accelerators, the most popular and ubiquitous being the GPU. We support virtualization of non-GPU devices through this infrastructure. These devices are exposed to user-space and used by various API and framework, such as CUDA, OpenCL, OpenVINO, OneAPI, DX12, etc...

One critical piece of feedback, provided by the community in our earlier submission, was the lack of an open source user-space to go along with our kernel compute driver. At the time we only had CUDA and DX12 user-space APIs, both of which being closed source. This is a divisive issue in the community and is heavily debated (https://lwn.net/Articles/821817/).

We took this feedback to heart and we spent the last year working on a way to address this key piece of feedback. Working closely with our partner Intel, we're happy to say that we now have a fully open source user-space for the OpenCL, OpenVINO and OneAPI compute family of APIs on Intel GPU platforms. This is supported by this open source project
(https://github.com/intel/compute-runtime).

To make it easy for our partners to build compute drivers, which are usable in both Windows and WSL environment, we provide a library, that provides a stable interface to our compute device abstraction. This was originally part of the libdxcore closed source API, but have now spawn that off into it's own open source project (https://github.com/microsoft/libdxg).

Between the Intel compute runtime project and libdxg, we now have a fully open source implementation of our virtualized compute stack inside of WSL. We will continue to support both open source user-space API against our compute abstraction as well as closed source one (CUDA, DX12), leaving it to the API owners and partners to decide what makes the most sense for them.

A lot of efforts went into addressing community feedback in this revised set of patches and we hope this is getting closer to what the community would like to see.

We're looking forward additional feedback.

Driver overview
-------------------------------------------------------
dxgkrnl is a driver for Hyper-V virtual compute devices, such as vGPU devices, which are projected to a Linux virtual machine (VM) by a Windows host. dxgkrnl works in context of WDDM (Windows Display Driver Model) for GPU or MCDM (Microsoft Compute Driver Model) for non-GPU devices. WDDM/MCDM consists of the following components:
- Graphics or Compute applications
- A graphics or compute user mode API (for example OpenGL, Vulkan, OpenCL, OpenVINO, OneAPI, CUDA, DX12, ...)
- User Mode Driver (UMD), written by a hardware vendor
- optional libdxg library helping UMD portability across Windows and Linux
- dxgkrnl Linux kernel driver (this driver)
- Kernel mode port driver on the Windows host (dxgkrnl.sys / dxgmms*.sys)
- Kernel Mode miniport driver (KMD) on the Windows host, written by a hardware vendor running on the Windows host and interfacing with the hardware device.

dxgkrnl exposes a subset the WDDM/MCDM D3DKMT interface to user space. See
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmthk/
This interface provides user space with an abstracted view and control of compute devices in a portable way across Windows and WSL. It is used for devices such as GPU or AI/ML processors. This interface is mapped to custom IOCTLs on Linux (see d3dkmthk.h).

A more detailed overview of this architecture is available here:
https://devblogs.microsoft.com/directx/directx-heart-linux/

Compute devices are paravirtualized, meaning that the actual communication with the corresponding device happens on the host. The version of dxgkrnl inside of the Linux kernel coordinates with the version of dxgkrnl running on Windows to provide a consistent and portable abstraction for the device that the various APIs and UMD can rely on across Windows and Linux.

Dxgkrnl creates the /dev/dxg device, which can be used to enumerate devices. UMD or an API runtime open the device and send ioctls to create various device objects (dxgdevice, dxgcontext, dxgallocation, etc., defined in dxgkrnl.h) and to submit work to the device. The WDDM objects are represented in user mode as opaque handles (struct d3dkmthandle). Dxgkrnl creates a dxgprocess object for each process, which opens the /dev/dxg device. This object has a handle table, which is used to translate d3dkmt handles to kernel objects. Handle table definitions are in hmgr.h. There is also a global handle table for objects, which do not belong to a particular process.

Driver initialization
-------------------------------------------------------
When dxgkrnl is loaded, dxgkrnl registers for virtual PCI device arrival notifications and VM bus channel device notifications (see dxgmodule.c). When the first virtual device is started, dxgkrnl creates a misc device (/dev/dxg). A user mode client can open the /dev/dxg device and send IOCTLs to enumerate and control virtual compute devices.

Virtual device initialization
-------------------------------------------------------
A virtual device is represented by a dxgadapter object. It is created when the corresponding device arrives on the virtual PCI bus. The device vendor is PCI_VENDOR_ID_MICROSOFT and the device id is PCI_DEVICE_ID_VIRTUAL_RENDER. The adapter is started when the corresponding VM bus channel and the global VM bus channel are initialized.
Dynamic arrival/removal of devices is supported.

Internal objects
-------------------------------------------------------
Dxgkrnl creates various internal objects in response to IOCTL calls. The corresponsing objects are also created on the host. Each object is placed to a process or global handle table. Object handles (d3dkmthandle) are returned to user mode. The object handles are also used to reference objects on the host. Corresponding objects in the guest and the host have the same handle value to avoid handle translation. The internal objects are:
- dxgadapter
Represents a virtual device object. It is created for every device projected by the host to the VM.
- dxgprocess
The object is created for each Linux process, which opens /dxg/dev. It has the object handle table, which holds pointers to all internal objects, which are created by this process.
- dxgcontext
Represents a device execution thread in the packet scheduling mode (as oppose to the hardware scheduling mode).
- dxghwqueue
Represents a device execution thread in the hardware scheduling mode.
- dxgdevice
A collection of device contexts, allocations, resources, sync objects, etc.
- dxgallocation
Represents a device accessible memory allocation.
- dxgresource
A collection of dxgallocation objects. This object could be shared between devices and processes.
- dxgsharedresource
Represents a dxgresource object, which is sharable between processes.
- dxgsyncobject
Represents a device synchronization object, which is used to synchronize execution of the device execution contexts.
- dxgsharedsyncobject
Represent a device synchronization object, which is sharable between processes.
- dxgpagingqueue
Represents a queue, which is used to manage residency of the device allocation objects.

Communications with the host
-------------------------------------------------------
Dxgkrnl communicates with the host via Hyper-V VM bus channels. There is a global channel and a per device channel. The VM bus messages are defined in dxgvmbus.h and the implementation is in dxgvmbus.c.

Most VM bus messages to the host are synchronous. When the host enables the asynchronous mode, some high frequency VM bus messages are sent asynchronously to improve performance. When async messages are enabled, all VM bus messages are sent only via the global channel to maintain the order of messages on the host.

The host could send asynchronous messages to dxgkrnl via the global VM bus channel. The host messages are handled by dxgvmbuschannel_receive().

PCI config space of the device is used to exchange information between the host and the guest during dxgkrnl initialization. Look at dxg_pci_probe_device().

CPU access to device accessible allocations
-------------------------------------------------------
D3DKMT API allows creation of allocations, which are accessible by the device and the CPU. The global VM bus channels has associated IO space, which is used to implement CPU access to CPU visible allocations. For each such allocation the host allocates a portion of the guest IO space and maps it to the allocation memory (it could be in system memory or in device local memory). A user mode application calls the LX_DXLOCK2 ioctl to get the allocation CPU address. Dxgkrnl uses vm_mmap to allocate a user space VA range and maps it to the allocation IO space using io_remap_pfn_range(). This way Linux user mode virtual addresses point to the host system memory or device local memory.

Sharing objects between processes
-------------------------------------------------------
Some dxgkrnl objects could be shared between processes. This includes resources (dxgresource) and synchronization objects (dxgsyncobject).
The WDDM API provides a way to share objects using so called "NT handles". "NT handle" on Windows is a native Windows process handle (HANDLE). "NT handles" are implemented as file descriptors (FD) on Linux.
The LX_DXSHAREOBJECTS ioctl is used to get an FD for a shared object. Before a shared object can be used, it needs to be "opened" to get the "local" d3dkmthandle handle. The LX_DXOPENRESOURCEFROMNTHANDLE and LX_DXOPENSYNCOBJECTFROMNTHANDLE2 aioctls re used to open a shared object.

Iouri Tarassov (24):
drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
drivers: hv: dxgkrnl: Open device file and dxgprocess creation
drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects
drivers: hv: dxgkrnl: Creation of dxgdevice
drivers: hv: dxgkrnl: Creation of dxgcontext objects
drivers: hv: dxgkrnl: Creation of GPU allocations and resources
drivers: hv: dxgkrnl: Create and destroy GPU sync objects
drivers: hv: dxgkrnl: Operations using GPU sync objects
drivers: hv: dxgkrnl: Sharing of dxgresource objects
drivers: hv: dxgkrnl: Sharing of sync objects
drivers: hv: dxgkrnl: Creation of hardware queue. Sync object
operations to hw queue.
drivers: hv: dxgkrnl: Creation of paging queue objects.
drivers: hv: dxgkrnl: Submit execution commands to the compute device
drivers: hv: dxgkrnl: Implement LX_DXSHAREOBJECTWITHHOST ioctl
drivers: hv: dxgkrnl: IOCTL to get the dxgdevice state
LX_DXGETDEVICESTATE
drivers: hv: dxgkrnl: Mmap(unmap) CPU address to device allocation:
LX_DXLOCK2, LX_DXUNLOCK2
drivers: hv: dxgkrnl: IOCTLs to handle GPU allocation properties
drivers: hv: dxgkrnl: Various simple IOCTLs and unused ones
LX_DXQUERYVIDEOMEMORYINFO, LX_DXFLUSHHEAPTRANSITIONS, LX_DXINVALIDATECACHE LX_DXGETSHAREDRESOURCEADAPTERLUID
drivers: hv: dxgkrnl: Simple IOCTLs LX_DXESCAPE,
LX_DXMARKDEVICEASERROR, LX_DXQUERYSTATISTICS, LX_DXQUERYCLOCKCALIBRATION
drivers: hv: dxgkrnl: IOCTLs to offer and reclaim allocations
drivers: hv: dxgkrnl: Ioctls to set/get scheduling priority
drivers: hv: dxgkrnl: IOCTLs to manage allocation residency
drivers: hv: dxgkrnl: IOCTLs to handle GPU virtual addressing (GPU VA)
drivers: hv: dxgkrnl: Add support to map guest pages by host

 MAINTAINERS                     |    7 +
 drivers/hv/Kconfig              |    2 +
 drivers/hv/Makefile             |    1 +
 drivers/hv/dxgkrnl/Kconfig      |   26 +
 drivers/hv/dxgkrnl/Makefile     |    5 +
 drivers/hv/dxgkrnl/dxgadapter.c | 1371 ++++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  956 ++++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  942 ++++++
 drivers/hv/dxgkrnl/dxgprocess.c |  334 ++
 drivers/hv/dxgkrnl/dxgvmbus.c   | 3750 +++++++++++++++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  882 +++++
 drivers/hv/dxgkrnl/hmgr.c       |  566 ++++
 drivers/hv/dxgkrnl/hmgr.h       |  112 +
 drivers/hv/dxgkrnl/ioctl.c      | 5450 +++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/misc.c       |   43 +
 drivers/hv/dxgkrnl/misc.h       |   96 +
 include/linux/hyperv.h          |   16 +
 include/uapi/misc/d3dkmthk.h    | 1945 +++++++++++
 18 files changed, 16504 insertions(+)
 create mode 100644 drivers/hv/dxgkrnl/Kconfig
 create mode 100644 drivers/hv/dxgkrnl/Makefile
 create mode 100644 drivers/hv/dxgkrnl/dxgadapter.c
 create mode 100644 drivers/hv/dxgkrnl/dxgkrnl.h
 create mode 100644 drivers/hv/dxgkrnl/dxgmodule.c
 create mode 100644 drivers/hv/dxgkrnl/dxgprocess.c
 create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.c
 create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.h
 create mode 100644 drivers/hv/dxgkrnl/hmgr.c
 create mode 100644 drivers/hv/dxgkrnl/hmgr.h
 create mode 100644 drivers/hv/dxgkrnl/ioctl.c
 create mode 100644 drivers/hv/dxgkrnl/misc.c
 create mode 100644 drivers/hv/dxgkrnl/misc.h
 create mode 100644 include/uapi/misc/d3dkmthk.h

--
2.35.1

#1 lore raw

PATCH v2 1/24 drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

This is the first commit for adding support for a Hyper-V based vGPU implementation that exposes the DirectX API to Linux userspace.

- Handle driver loading, registration for the PCI and VM bus device notifications
- Add headers for user mode interfaces, internal driver objects and VM bus communication interface
- Handle initialization of VM bus channels and creation of the dxgadapter object
- Connect the dxgkrnl module to the drivers/hv/ makefile and Kconfig.
- Create a MAINTAINERS entry

A PCI device is created for each virtual GPU (vGPU) device, projected by the host. The device vendor is PCI_VENDOR_ID_MICROSOFT and device id is PCI_DEVICE_ID_VIRTUAL_RENDER. dxg_pci_probe_device handles arrival of such devices and it creates dxgadapter objects. The PCI config space of the vGPU device has luid of the corresponding per GPU VM bus channel. This is how the adapters are linked to VM bus channels.

A dxgadapter object represents a virtual GPU, projected to the VM by the host. This object can start functioning only when the global VM bus channel and the corresponding per vGPU VM bus channel are initialized in the guest. Notifications about arrival of vGPU PCI device and VM bus channels can happen in any order. Therefore, the initial dxgadapter object state is DXGADAPTER_STATE_WAITING_VMBUS. A list of VM bus channels and a list of dxgadapter objects are created. When dxgkrnl is notified about a VM bus channel arrival, if tries to start all adapters, which are not started yet.

VM bus interface version is exchanged by reading/writing the PCI config space of the vGPU device.

---
 MAINTAINERS                     |    7 +
 drivers/hv/Kconfig              |    2 +
 drivers/hv/Makefile             |    1 +
 drivers/hv/dxgkrnl/Kconfig      |   26 +
 drivers/hv/dxgkrnl/Makefile     |    5 +
 drivers/hv/dxgkrnl/dxgadapter.c |  172 +++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  223 ++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  736 ++++++++++++
 drivers/hv/dxgkrnl/dxgprocess.c |   17 +
 drivers/hv/dxgkrnl/dxgvmbus.c   |  578 +++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  855 ++++++++++++++
 drivers/hv/dxgkrnl/hmgr.c       |   23 +
 drivers/hv/dxgkrnl/hmgr.h       |   75 ++
 drivers/hv/dxgkrnl/ioctl.c      |   24 +
 drivers/hv/dxgkrnl/misc.c       |   37 +
 drivers/hv/dxgkrnl/misc.h       |   89 ++
 include/linux/hyperv.h          |   16 +
 include/uapi/misc/d3dkmthk.h    | 1945 +++++++++++++++++++++++++++++++
 18 files changed, 4831 insertions(+)
 create mode 100644 drivers/hv/dxgkrnl/Kconfig
 create mode 100644 drivers/hv/dxgkrnl/Makefile
 create mode 100644 drivers/hv/dxgkrnl/dxgadapter.c
 create mode 100644 drivers/hv/dxgkrnl/dxgkrnl.h
 create mode 100644 drivers/hv/dxgkrnl/dxgmodule.c
 create mode 100644 drivers/hv/dxgkrnl/dxgprocess.c
 create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.c
 create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.h
 create mode 100644 drivers/hv/dxgkrnl/hmgr.c
 create mode 100644 drivers/hv/dxgkrnl/hmgr.h
 create mode 100644 drivers/hv/dxgkrnl/ioctl.c
 create mode 100644 drivers/hv/dxgkrnl/misc.c
 create mode 100644 drivers/hv/dxgkrnl/misc.h
 create mode 100644 include/uapi/misc/d3dkmthk.h
MAINTAINERS +7 -0
index a2bd991db512..5856e09d834c 100644
@@ -8841,6 +8841,13 @@ F:	Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml
 F:	drivers/mtd/hyperbus/
 F:	include/linux/mtd/hyperbus.h
 
+Hyper-V vGPU DRIVER
+M:	Iouri Tarassov <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	drivers/hv/dxgkrnl/
+F:	include/uapi/misc/d3dkmthk.h
+
 HYPERVISOR VIRTUAL CONSOLE DRIVER
 L:	[email protected]
 S:	Odd Fixes
drivers/hv/Kconfig +2 -0
index dd12af20e467..7006f7b66200 100644
@@ -29,4 +29,6 @@ config HYPERV_BALLOON
 	help
 	  Select this option to enable Hyper-V Balloon driver.
 
+source "drivers/hv/dxgkrnl/Kconfig"
+
 endmenu
drivers/hv/Makefile +1 -0
index d76df5c8c2a9..aa1cbdb5d0d2 100644
@@ -2,6 +2,7 @@
 obj-$(CONFIG_HYPERV)		+= hv_vmbus.o
 obj-$(CONFIG_HYPERV_UTILS)	+= hv_utils.o
 obj-$(CONFIG_HYPERV_BALLOON)	+= hv_balloon.o
+obj-$(CONFIG_DXGKRNL)		+= dxgkrnl/
 
 CFLAGS_hv_trace.o = -I$(src)
 CFLAGS_hv_balloon.o = -I$(src)
drivers/hv/dxgkrnl/Kconfig new file +26 -0
new file mode 100644
index 000000000000..22d0914d8f1e
@@ -0,0 +1,26 @@
+#
+# dxgkrnl configuration
+#
+
+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
+	  <https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmthk/>
+	  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.
drivers/hv/dxgkrnl/Makefile new file +5 -0
new file mode 100644
index 000000000000..745c66bebe5d
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for the Linux video drivers.
+
+obj-$(CONFIG_DXGKRNL)	+= dxgkrnl.o
+dxgkrnl-y		:= dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
drivers/hv/dxgkrnl/dxgadapter.c new file +172 -0

172 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgkrnl.h new file +223 -0

223 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgmodule.c new file +736 -0

736 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgprocess.c new file +17 -0
new file mode 100644
index 000000000000..81e5b4a137e7
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2019, Microsoft Corporation.
+ *
+ * Author:
+ *   Iouri Tarassov <[email protected]>
+ *
+ * Dxgkrnl Graphics Driver
+ * DXGPROCESS implementation
+ *
+ */
+
+#include "dxgkrnl.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"dxgk: " fmt
drivers/hv/dxgkrnl/dxgvmbus.c new file +578 -0

578 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.h new file +855 -0

855 lines not on this page · raw message

drivers/hv/dxgkrnl/hmgr.c new file +23 -0
new file mode 100644
index 000000000000..216e0956f8f8
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2019, Microsoft Corporation.
+ *
+ * Author:
+ *   Iouri Tarassov <[email protected]>
+ *
+ * Dxgkrnl Graphics Driver
+ * Handle manager implementation
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+
+#include "misc.h"
+#include "dxgkrnl.h"
+#include "hmgr.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"dxgk: " fmt
drivers/hv/dxgkrnl/hmgr.h new file +75 -0

75 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c new file +24 -0
new file mode 100644
index 000000000000..277e25e5d8c6
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2019, Microsoft Corporation.
+ *
+ * Author:
+ *   Iouri Tarassov <[email protected]>
+ *
+ * Dxgkrnl Graphics Driver
+ * Ioctl implementation
+ *
+ */
+
+#include <linux/eventfd.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/anon_inodes.h>
+#include <linux/mman.h>
+
+#include "dxgkrnl.h"
+#include "dxgvmbus.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt)	"dxgk: " fmt
drivers/hv/dxgkrnl/misc.c new file +37 -0
new file mode 100644
index 000000000000..cb1e0635bebc
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2019, Microsoft Corporation.
+ *
+ * Author:
+ *   Iouri Tarassov <[email protected]>
+ *
+ * Dxgkrnl Graphics Driver
+ * Helper functions
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#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 = 0; i < n; i++) {
+		dest[i] = src[i];
+		if (src[i] == 0) {
+			i++;
+			break;
+		}
+	}
+	dest[i - 1] = 0;
+	return dest;
+}
drivers/hv/dxgkrnl/misc.h new file +89 -0

89 lines not on this page · raw message

include/linux/hyperv.h +16 -0
index b823311eac79..9d21055b003d 100644
@@ -1414,6 +1414,22 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size);
 	.guid = GUID_INIT(0xda0a7802, 0xe377, 0x4aac, 0x8e, 0x77, \
 			  0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8)
 
+/*
+ * GPU paravirtualization global DXGK channel
+ * {DDE9CBC0-5060-4436-9448-EA1254A5D177}
+ */
+#define HV_GPUP_DXGK_GLOBAL_GUID \
+	.guid = GUID_INIT(0xdde9cbc0, 0x5060, 0x4436, 0x94, 0x48, \
+			  0xea, 0x12, 0x54, 0xa5, 0xd1, 0x77)
+
+/*
+ * GPU paravirtualization per virtual GPU DXGK channel
+ * {6E382D18-3336-4F4B-ACC4-2B7703D4DF4A}
+ */
+#define HV_GPUP_DXGK_VGPU_GUID \
+	.guid = GUID_INIT(0x6e382d18, 0x3336, 0x4f4b, 0xac, 0xc4, \
+			  0x2b, 0x77, 0x3, 0xd4, 0xdf, 0x4a)
+
 /*
  * Synthetic FC GUID
  * {2f9bcc4a-0069-4af3-b76b-6fd0be528cda}
include/uapi/misc/d3dkmthk.h new file +1945 -0

92 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.35.1

Part of the diff is not shown here. View the raw message.

#2 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

I love your patch! Yet something to improve:

Hi Iouri,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.17-rc2 next-20220204]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Iouri-Tarassov/Driver-for-Hyper-v-virtual-compute-device/20220205-103726
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 0457e5153e0e8420134f60921349099e907264ca
config: x86_64-randconfig-a004-20220131 (https://download.01.org/0day-ci/archive/20220205/202202051359.j7N6kn2E-lkp(a)intel.com/config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/7a6280c6fb18da7243d3de07abe09b4c3d1938e2
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Iouri-Tarassov/Driver-for-Hyper-v-virtual-compute-device/20220205-103726
        git checkout 7a6280c6fb18da7243d3de07abe09b4c3d1938e2
        # save the config file to linux build tree
        mkdir build_dir
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate

All errors (new ones prefixed by >>):

In file included from <command-line>:32:

>> ./usr/include/misc/d3dkmthk.h:25:4: error: unknown type name '__u32'
      25 |    __u32 instance :  6;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:26:4: error: unknown type name '__u32'
      26 |    __u32 index : 24;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:27:4: error: unknown type name '__u32'
      27 |    __u32 unique : 2;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:29:3: error: unknown type name '__u32'
      29 |   __u32 v;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:53:2: error: unknown type name '__u32'
      53 |  __u32 a;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:54:2: error: unknown type name '__u32'
      54 |  __u32 b;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:70:2: error: unknown type name '__u32'
      70 |  __u32    num_sources;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:71:2: error: unknown type name '__u32'
      71 |  __u32    present_move_regions_preferred;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:75:2: error: unknown type name '__u32'
      75 |  __u32    num_adapters;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:76:2: error: unknown type name '__u32'
      76 |  __u32    reserved;
         |  ^~~~~
>> ./usr/include/misc/d3dkmthk.h:77:2: error: unknown type name '__u64'
      77 |  __u64    *adapters;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:93:4: error: unknown type name '__u32'
      93 |    __u32  write_operation  :1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:94:4: error: unknown type name '__u32'
      94 |    __u32  do_not_retire_instance :1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:95:4: error: unknown type name '__u32'
      95 |    __u32  offer_priority  :3;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:96:4: error: unknown type name '__u32'
      96 |    __u32  reserved  :27;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:98:3: error: unknown type name '__u32'
      98 |   __u32   value;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:103:2: error: unknown type name '__u32'
     103 |  __u32    allocation_index;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:106:4: error: unknown type name '__u32'
     106 |    __u32  slot_id:24;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:107:4: error: unknown type name '__u32'
     107 |    __u32  reserved:8;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:109:3: error: unknown type name '__u32'
     109 |   __u32   value;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:111:2: error: unknown type name '__u32'
     111 |  __u32    driver_id;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:112:2: error: unknown type name '__u32'
     112 |  __u32    allocation_offset;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:113:2: error: unknown type name '__u32'
     113 |  __u32    patch_offset;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:114:2: error: unknown type name '__u32'
     114 |  __u32    split_offset;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:118:2: error: unknown type name '__u32'
     118 |  __u32    legacy_mode:1;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:119:2: error: unknown type name '__u32'
     119 |  __u32    request_vSync:1;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:120:2: error: unknown type name '__u32'
     120 |  __u32    disable_gpu_timeout:1;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:121:2: error: unknown type name '__u32'
     121 |  __u32    gdi_device:1;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:122:2: error: unknown type name '__u32'
     122 |  __u32    reserved:28;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:127:2: error: unknown type name '__u32'
     127 |  __u32    reserved3;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:130:2: error: unknown type name '__u64'
     130 |  __u64    command_buffer;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:131:2: error: unknown type name '__u32'
     131 |  __u32    command_buffer_size;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:132:2: error: unknown type name '__u32'
     132 |  __u32    reserved;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:133:2: error: unknown type name '__u64'
     133 |  __u64    allocation_list;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:134:2: error: unknown type name '__u32'
     134 |  __u32    allocation_list_size;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:135:2: error: unknown type name '__u32'
     135 |  __u32    reserved1;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:136:2: error: unknown type name '__u64'
     136 |  __u64    patch_location_list;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:137:2: error: unknown type name '__u32'
     137 |  __u32    patch_location_list_size;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:138:2: error: unknown type name '__u32'
     138 |  __u32    reserved2;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:158:4: error: unknown type name '__u32'
     158 |    __u32  null_rendering:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:159:4: error: unknown type name '__u32'
     159 |    __u32  initial_data:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:160:4: error: unknown type name '__u32'
     160 |    __u32  disable_gpu_timeout:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:161:4: error: unknown type name '__u32'
     161 |    __u32  synchronization_only:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:162:4: error: unknown type name '__u32'
     162 |    __u32  hw_queue_supported:1;
--
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:365:2: error: unknown type name '__u64'
     365 |  __u64    allocation_info;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:367:2: error: unknown type name '__u32'
     367 |  __u32    reserved2;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:368:2: error: unknown type name '__u64'
     368 |  __u64    private_runtime_resource_handle;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:374:4: error: unknown type name '__u32'
     374 |    __u32  assume_not_in_use:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:375:4: error: unknown type name '__u32'
     375 |    __u32  synchronous_destroy:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:376:4: error: unknown type name '__u32'
     376 |    __u32  reserved:29;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:377:4: error: unknown type name '__u32'
     377 |    __u32  system_use_only:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:379:3: error: unknown type name '__u32'
     379 |   __u32   value;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:386:2: error: unknown type name '__u64'
     386 |  __u64    allocations;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:387:2: error: unknown type name '__u32'
     387 |  __u32    alloc_count;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:394:4: error: unknown type name '__u32'
     394 |    __u32  cant_trim_further:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:395:4: error: unknown type name '__u32'
     395 |    __u32  must_succeed:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:396:4: error: unknown type name '__u32'
     396 |    __u32  reserved:30;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:398:3: error: unknown type name '__u32'
     398 |   __u32   value;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:404:2: error: unknown type name '__u32'
     404 |  __u32    alloc_count;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:405:2: error: unknown type name '__u64'
     405 |  __u64    allocation_list;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:406:2: error: unknown type name '__u64'
     406 |  __u64    priority_list;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:408:2: error: unknown type name '__u64'
     408 |  __u64    paging_fence_value;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:409:2: error: unknown type name '__u64'
     409 |  __u64    num_bytes_to_trim;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:415:4: error: unknown type name '__u32'
     415 |    __u32  evict_only_if_necessary:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:416:4: error: unknown type name '__u32'
     416 |    __u32  not_written_to:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:417:4: error: unknown type name '__u32'
     417 |    __u32  reserved:30;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:419:3: error: unknown type name '__u32'
     419 |   __u32   value;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:425:2: error: unknown type name '__u32'
     425 |  __u32    alloc_count;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:426:2: error: unknown type name '__u64'
     426 |  __u64    allocations;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:428:2: error: unknown type name '__u32'
     428 |  __u32    reserved;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:429:2: error: unknown type name '__u64'
     429 |  __u64    num_bytes_to_trim;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:435:4: error: unknown type name '__u64'
     435 |    __u64 write:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:436:4: error: unknown type name '__u64'
     436 |    __u64 execute:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:437:4: error: unknown type name '__u64'
     437 |    __u64 zero:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:438:4: error: unknown type name '__u64'
     438 |    __u64 no_access:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:439:4: error: unknown type name '__u64'
     439 |    __u64 system_use_only:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:440:4: error: unknown type name '__u64'
     440 |    __u64 reserved:59;
         |    ^~~~~
>> ./usr/include/misc/d3dkmthk.h:440:10: error: width of 'reserved' exceeds its type
     440 |    __u64 reserved:59;
         |          ^~~~~~~~
   ./usr/include/misc/d3dkmthk.h:442:3: error: unknown type name '__u64'
     442 |   __u64  value;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:457:4: error: unknown type name '__u64'
     457 |    __u64  base_address;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:458:4: error: unknown type name '__u64'
     458 |    __u64  size;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:460:4: error: unknown type name '__u64'
     460 |    __u64  allocation_offset;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:461:4: error: unknown type name '__u64'
     461 |    __u64  allocation_size;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:464:4: error: unknown type name '__u64'
     464 |    __u64  base_address;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:465:4: error: unknown type name '__u64'
     465 |    __u64  size;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:467:4: error: unknown type name '__u64'
     467 |    __u64  allocation_offset;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:468:4: error: unknown type name '__u64'
     468 |    __u64  allocation_size;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:470:4: error: unknown type name '__u64'
     470 |    __u64  driver_protection;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:473:4: error: unknown type name '__u64'
     473 |    __u64 base_address;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:474:4: error: unknown type name '__u64'
     474 |    __u64 size;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:478:4: error: unknown type name '__u64'
     478 |    __u64 source_address;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:479:4: error: unknown type name '__u64'
     479 |    __u64 size;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:480:4: error: unknown type name '__u64'
     480 |    __u64 dest_address;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:495:2: error: unknown type name '__u32'
     495 |  __u32     num_operations;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:496:2: error: unknown type name '__u64'
     496 |  __u64     operations;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:497:2: error: unknown type name '__u32'
     497 |  __u32     reserved0;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:498:2: error: unknown type name '__u32'
     498 |  __u32     reserved1;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:499:2: error: unknown type name '__u64'
     499 |  __u64     reserved2;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:500:2: error: unknown type name '__u64'
     500 |  __u64     fence_value;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:503:4: error: unknown type name '__u32'
     503 |    __u32   do_not_wait:1;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:504:4: error: unknown type name '__u32'
     504 |    __u32   reserved:31;
         |    ^~~~~
   ./usr/include/misc/d3dkmthk.h:506:3: error: unknown type name '__u32'
     506 |   __u32    value;
         |   ^~~~~
   ./usr/include/misc/d3dkmthk.h:508:2: error: unknown type name '__u32'
     508 |  __u32     reserved3;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:513:2: error: unknown type name '__u64'
     513 |  __u64     base_address;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:514:2: error: unknown type name '__u64'
     514 |  __u64     minimum_address;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:515:2: error: unknown type name '__u64'
     515 |  __u64     maximum_address;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:517:2: error: unknown type name '__u64'
     517 |  __u64     offset_in_pages;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:518:2: error: unknown type name '__u64'
     518 |  __u64     size_in_pages;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:520:2: error: unknown type name '__u64'
     520 |  __u64     driver_protection;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:521:2: error: unknown type name '__u32'
     521 |  __u32     reserved0;
         |  ^~~~~
   ./usr/include/misc/d3dkmthk.h:522:2: error: unknown type name '__u64'
     522 |  __u64     reserved1;

..

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

#3 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

In reply to Iouri Tarassov
Quoted 2 lines · Iouri Tarassov

This is the first commit for adding support for a Hyper-V based vGPU implementation that exposes the DirectX API to Linux userspace.

"This is the first commit" doesn't need to be in the changelog, right? Please read the documentation for how to write a changelog text, and look at all of the thousands of examples on the mailing list of others.

Also, it would help if this patch would build :(

#4 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

In reply to Iouri Tarassov
Quoted 7 lines · Iouri Tarassov

This is the first commit for adding support for a Hyper-V based vGPU implementation that exposes the DirectX API to Linux userspace.

- Handle driver loading, registration for the PCI and VM bus device notifications
- Add headers for user mode interfaces, internal driver objects and VM bus communication interface

Only add the interfaces for the changes that you need in this commit. Do not add them all and then use them later, that makes it impossible to review.

Quoted 38 lines

- Handle initialization of VM bus channels and creation of the dxgadapter object
- Connect the dxgkrnl module to the drivers/hv/ makefile and Kconfig.
- Create a MAINTAINERS entry

A PCI device is created for each virtual GPU (vGPU) device, projected by the host. The device vendor is PCI_VENDOR_ID_MICROSOFT and device id is PCI_DEVICE_ID_VIRTUAL_RENDER. dxg_pci_probe_device handles arrival of such devices and it creates dxgadapter objects. The PCI config space of the vGPU device has luid of the corresponding per GPU VM bus channel. This is how the adapters are linked to VM bus channels.

A dxgadapter object represents a virtual GPU, projected to the VM by the host. This object can start functioning only when the global VM bus channel and the corresponding per vGPU VM bus channel are initialized in the guest. Notifications about arrival of vGPU PCI device and VM bus channels can happen in any order. Therefore, the initial dxgadapter object state is DXGADAPTER_STATE_WAITING_VMBUS. A list of VM bus channels and a list of dxgadapter objects are created. When dxgkrnl is notified about a VM bus channel arrival, if tries to start all adapters, which are not started yet.

VM bus interface version is exchanged by reading/writing the PCI config space of the vGPU device.

---
 MAINTAINERS                     |    7 +
 drivers/hv/Kconfig              |    2 +
 drivers/hv/Makefile             |    1 +
 drivers/hv/dxgkrnl/Kconfig      |   26 +
 drivers/hv/dxgkrnl/Makefile     |    5 +
 drivers/hv/dxgkrnl/dxgadapter.c |  172 +++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  223 ++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  736 ++++++++++++
 drivers/hv/dxgkrnl/dxgprocess.c |   17 +
 drivers/hv/dxgkrnl/dxgvmbus.c   |  578 +++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  855 ++++++++++++++
Quoted 8 lines
 drivers/hv/dxgkrnl/hmgr.c       |   23 +
 drivers/hv/dxgkrnl/hmgr.h       |   75 ++
 drivers/hv/dxgkrnl/ioctl.c      |   24 +
 drivers/hv/dxgkrnl/misc.c       |   37 +
 drivers/hv/dxgkrnl/misc.h       |   89 ++
 include/linux/hyperv.h          |   16 +
 include/uapi/misc/d3dkmthk.h    | 1945 +++++++++++++++++++++++++++++++
 18 files changed, 4831 insertions(+)

Would you want to review a 4800 line patch all at once?

Please take some time and review other commits on the mailing list and offer up your comments to them. That will help you understand how to create your own changes better.

thanks,

greg k-h

#5 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

Quoted 30 lines · Greg KH
Quoted 3 lines · Iouri Tarassov

This is the first commit for adding support for a Hyper-V based vGPU implementation that exposes the DirectX API to Linux userspace.

Only add the interfaces for the changes that you need in this commit. Do not add them all and then use them later, that makes it impossible to review.

Quoted 12 lines
---
 MAINTAINERS                     |    7 +
 drivers/hv/Kconfig              |    2 +
 drivers/hv/Makefile             |    1 +
 drivers/hv/dxgkrnl/Kconfig      |   26 +
 drivers/hv/dxgkrnl/Makefile     |    5 +
 drivers/hv/dxgkrnl/dxgadapter.c |  172 +++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  223 ++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  736 ++++++++++++
 drivers/hv/dxgkrnl/dxgprocess.c |   17 +
 drivers/hv/dxgkrnl/dxgvmbus.c   |  578 +++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  855 ++++++++++++++
Quoted 8 lines
 drivers/hv/dxgkrnl/hmgr.c       |   23 +
 drivers/hv/dxgkrnl/hmgr.h       |   75 ++
 drivers/hv/dxgkrnl/ioctl.c      |   24 +
 drivers/hv/dxgkrnl/misc.c       |   37 +
 drivers/hv/dxgkrnl/misc.h       |   89 ++
 include/linux/hyperv.h          |   16 +
 include/uapi/misc/d3dkmthk.h    | 1945 +++++++++++++++++++++++++++++++
 18 files changed, 4831 insertions(+)
Quoted 3 lines

Would you want to review a 4800 line patch all at once?

greg k-h

Hi Greg,

Thank you for reviewing. I appreciate your time.

I am trying to find compromise between the number of patches and making review easy. There are about 70 IOCTLs in the driver interface, so having a patch for every IOCTL seems excessive.

I tried to add only definitions for the internal objects, which are used in the patch.

1. d3dkmthk.h defines the user mode interface structures. This is ported from the windows header at once. Is it acceptable to add it at it is?

2. dxgvmbus.h defines the VM bus interface between the linux guest and the host. It was ported from the windows version at once. Is it acceptable to add it as it is?

3. Is it acceptable to combine logically connected IOCTLs to a single patch?
For example, IOCTLs for creation/destruction sync object and submission of wait/signal operations.

Thanks
Iouri

#6 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

Quoted 45 lines · Iouri Tarassov
Quoted 30 lines · Greg KH
Quoted 3 lines · Iouri Tarassov

This is the first commit for adding support for a Hyper-V based vGPU implementation that exposes the DirectX API to Linux userspace.

Only add the interfaces for the changes that you need in this commit. Do not add them all and then use them later, that makes it impossible to review.

Quoted 12 lines
---
 MAINTAINERS                     |    7 +
 drivers/hv/Kconfig              |    2 +
 drivers/hv/Makefile             |    1 +
 drivers/hv/dxgkrnl/Kconfig      |   26 +
 drivers/hv/dxgkrnl/Makefile     |    5 +
 drivers/hv/dxgkrnl/dxgadapter.c |  172 +++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  223 ++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  736 ++++++++++++
 drivers/hv/dxgkrnl/dxgprocess.c |   17 +
 drivers/hv/dxgkrnl/dxgvmbus.c   |  578 +++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  855 ++++++++++++++
Quoted 8 lines
 drivers/hv/dxgkrnl/hmgr.c       |   23 +
 drivers/hv/dxgkrnl/hmgr.h       |   75 ++
 drivers/hv/dxgkrnl/ioctl.c      |   24 +
 drivers/hv/dxgkrnl/misc.c       |   37 +
 drivers/hv/dxgkrnl/misc.h       |   89 ++
 include/linux/hyperv.h          |   16 +
 include/uapi/misc/d3dkmthk.h    | 1945 +++++++++++++++++++++++++++++++
 18 files changed, 4831 insertions(+)
Quoted 3 lines

Would you want to review a 4800 line patch all at once?

greg k-h

Hi Greg,

Thank you for reviewing. I appreciate your time.

I am trying to find compromise between the number of patches and making review easy. There are about 70 IOCTLs in the driver interface, so having a patch
for every IOCTL seems excessive.

Quoted 6 lines

I tried to add only definitions for the internal objects, which are used in the patch.

1. d3dkmthk.h defines the user mode interface structures. This is ported from
 the windows header at once. Is it acceptable to add it at it is?

No, again, would you want to be presented with code that is not used at all? How would you want this to look if you had to review this?

Quoted 4 lines

2. dxgvmbus.h defines the VM bus interface between the linux guest and the host.
It was ported from the windows version at once. Is it acceptable to add it as it is?

Again, no.

Quoted 3 lines

3. Is it acceptable to combine logically connected IOCTLs to a single patch? For example, IOCTLs for creation/destruction sync object and submission of wait/signal operations.

Yes, that makes sense.

Again, what would you want here if you had to review all of this?

I suggest stopping and taking some time and start reviewing code on the mailing lists first. Look at how others are doing this for large new features, and offer up your review to those changes. That will give you the experience for how to do it yourself. To expect to do this all correct the first time without ever being on the other side of the process very difficult.

thanks,

greg k-h

#7 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

Hi Greg,

Quoted 39 lines · Greg KH
Quoted 38 lines · Iouri Tarassov
Quoted 30 lines · Greg KH
Quoted 3 lines · Iouri Tarassov

This is the first commit for adding support for a Hyper-V based vGPU implementation that exposes the DirectX API to Linux userspace.

Only add the interfaces for the changes that you need in this commit. Do not add them all and then use them later, that makes it impossible to review.

Quoted 12 lines
---
 MAINTAINERS                     |    7 +
 drivers/hv/Kconfig              |    2 +
 drivers/hv/Makefile             |    1 +
 drivers/hv/dxgkrnl/Kconfig      |   26 +
 drivers/hv/dxgkrnl/Makefile     |    5 +
 drivers/hv/dxgkrnl/dxgadapter.c |  172 +++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  223 ++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  736 ++++++++++++
 drivers/hv/dxgkrnl/dxgprocess.c |   17 +
 drivers/hv/dxgkrnl/dxgvmbus.c   |  578 +++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  855 ++++++++++++++
Quoted 8 lines
 drivers/hv/dxgkrnl/hmgr.c       |   23 +
 drivers/hv/dxgkrnl/hmgr.h       |   75 ++
 drivers/hv/dxgkrnl/ioctl.c      |   24 +
 drivers/hv/dxgkrnl/misc.c       |   37 +
 drivers/hv/dxgkrnl/misc.h       |   89 ++
 include/linux/hyperv.h          |   16 +
 include/uapi/misc/d3dkmthk.h    | 1945 +++++++++++++++++++++++++++++++
 18 files changed, 4831 insertions(+)
Quoted 3 lines

Would you want to review a 4800 line patch all at once?

greg k-h

Hi Greg,

Quoted 8 lines
Quoted 5 lines

Thank you for reviewing. I appreciate your time.

1. d3dkmthk.h defines the user mode interface structures. This is ported from
 the windows header at once. Is it acceptable to add it at it is?

No, again, would you want to be presented with code that is not used at all? How would you want this to look if you had to review this?

Could you recommend a similar in size driver to look how it was first submitted?

I looked at the Habanalabs driver submission, which was signed off by you.

The commit 1ea2a20e91a4d0543a933b4df706c2585db7e3ae adds 94 header files, without using the definitions.

    habanalabs: add Goya registers header files
    This patch just adds a lot of header files that contain description of Goya's registers.

How did you review this? I do not see much difference between defining an interface to a virtual device and defining an interface to a hardware device.

d3dkmthk.h defines a binary interface to the compute driver. It cannot be changed, because it must be binary compatible with the Windows display graphics model.
In my opinion the only thing to review here is the usage of the correct Linux types and coding style. I can submit the file in a dedicated patch.

Quoted 6 lines
Quoted 4 lines

2. dxgvmbus.h defines the VM bus interface between the linux guest and the host.
It was ported from the windows version at once. Is it acceptable to add it as it is?

Again, no.

The same here.
dxgvmbus.h defines the binary VM bus interface between the host and guest.
It must be compatible with the existing interface.It cannot be changed.
In my opinion the only thing to review here is the usage of the correct Linux types and coding style. I can submit the file in a dedicated patch.

What are you looking to review in these interface? I am trying to avoid unnecessary work, but will do it if it really helps during review.

Thanks a lot,
Iouri

#8 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

In reply to Iouri Tarassov
Quoted 1 line · Iouri Tarassov

+Hyper-V vGPU DRIVER

This should be all caps.

#9 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

In reply to Iouri Tarassov

drivers/hv/dxgkrnl/Kconfig line 3

Quoted 6 lines · Iouri Tarassov
drivers/hv/dxgkrnl/Kconfig new file +3 -0
@@ -0,0 +1,26 @@
+#
+# dxgkrnl configuration
+#

No copyright? No SPDX line?

Did you run checkpatch.pl on this thing?

And we do not know what a "dgxkrnl" is. This is the kernel, so why say it again? And we have lots of vowels to use, please do so.

Quoted 29 lines
drivers/hv/dxgkrnl/Kconfig new file +23 -0
+
+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
+	  <https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmthk/>
+	  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.
drivers/hv/dxgkrnl/Makefile new file +0 -0
new file mode 100644
index 000000000000..745c66bebe5d

drivers/hv/dxgkrnl/Makefile line 2

Quoted 2 lines
drivers/hv/dxgkrnl/Makefile new file +2 -0
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for the Linux video drivers.

There's lots of linux video drivers in the kernel, this is not all of them here.

drivers/hv/dxgkrnl/dxgadapter.c line 4

Quoted 13 lines
drivers/hv/dxgkrnl/Makefile new file +3 -0
+
+obj-$(CONFIG_DXGKRNL)	+= dxgkrnl.o
+dxgkrnl-y		:= dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
drivers/hv/dxgkrnl/dxgadapter.c new file +4 -0
new file mode 100644
index 000000000000..e0a6fea00bd5
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2019, Microsoft Corporation.

Drop the trailing ',' in the copyright notice please, that's not how these should look like.

And I doubt you last touched this in 2019, right?

thanks,

greg k-h

#10 lore raw

Re: [PATCH v2 01/24] drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter

In reply to Iouri Tarassov
I love your patch! Yet something to improve:

Hi Iouri,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.17-rc2 next-20220204]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Iouri-Tarassov/Driver-for-Hyper-v-virtual-compute-device/20220205-103726
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 0457e5153e0e8420134f60921349099e907264ca
config: x86_64-randconfig-a011-20220131 (https://download.01.org/0day-ci/archive/20220205/202202051759.oGUDauQC-lkp(a)intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 78c6b90000292eb37aac5dead6ab26611cd76f42)

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/7a6280c6fb18da7243d3de07abe09b4c3d1938e2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Iouri-Tarassov/Driver-for-Hyper-v-virtual-compute-device/20220205-103726 git checkout 7a6280c6fb18da7243d3de07abe09b4c3d1938e2
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate

All errors (new ones prefixed by >>):

In file included from <built-in>:1:

>> ./usr/include/misc/d3dkmthk.h:25:4: error: unknown type name '__u32'
                           __u32 instance  :  6;
                           ^
   ./usr/include/misc/d3dkmthk.h:26:4: error: unknown type name '__u32'
                           __u32 index     : 24;
                           ^
   ./usr/include/misc/d3dkmthk.h:27:4: error: unknown type name '__u32'
                           __u32 unique    : 2;
                           ^
   ./usr/include/misc/d3dkmthk.h:29:3: error: unknown type name '__u32'
                   __u32 v;
                   ^
   ./usr/include/misc/d3dkmthk.h:53:2: error: unknown type name '__u32'
           __u32 a;
           ^
   ./usr/include/misc/d3dkmthk.h:54:2: error: unknown type name '__u32'
           __u32 b;
           ^
   ./usr/include/misc/d3dkmthk.h:70:2: error: unknown type name '__u32'
           __u32                           num_sources;
           ^
   ./usr/include/misc/d3dkmthk.h:71:2: error: unknown type name '__u32'
           __u32                           present_move_regions_preferred;
           ^
   ./usr/include/misc/d3dkmthk.h:75:2: error: unknown type name '__u32'
           __u32                           num_adapters;
           ^
   ./usr/include/misc/d3dkmthk.h:76:2: error: unknown type name '__u32'
           __u32                           reserved;
           ^
>> ./usr/include/misc/d3dkmthk.h:77:2: error: unknown type name '__u64'
           __u64                           *adapters;
           ^
   ./usr/include/misc/d3dkmthk.h:93:4: error: unknown type name '__u32'
                           __u32           write_operation         :1;
                           ^
   ./usr/include/misc/d3dkmthk.h:94:4: error: unknown type name '__u32'
                           __u32           do_not_retire_instance  :1;
                           ^
   ./usr/include/misc/d3dkmthk.h:95:4: error: unknown type name '__u32'
                           __u32           offer_priority          :3;
                           ^
   ./usr/include/misc/d3dkmthk.h:96:4: error: unknown type name '__u32'
                           __u32           reserved                :27;
                           ^
   ./usr/include/misc/d3dkmthk.h:98:3: error: unknown type name '__u32'
                   __u32                   value;
                   ^
   ./usr/include/misc/d3dkmthk.h:103:2: error: unknown type name '__u32'
           __u32                           allocation_index;
           ^
   ./usr/include/misc/d3dkmthk.h:106:4: error: unknown type name '__u32'
                           __u32           slot_id:24;
                           ^
   ./usr/include/misc/d3dkmthk.h:107:4: error: unknown type name '__u32'
                           __u32           reserved:8;
                           ^

fatal error: too many errors emitted, stopping now [-ferror-limit=] 20 errors generated.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

#11 lore raw

PATCH v2 2/24 drivers: hv: dxgkrnl: Open device file and dxgprocess creation

In reply to Iouri Tarassov

Implement opening of the device (/dev/dxg) file object and creation of dxgprocess. dxgprocess is created for each process, which opens /dev/dxg. dxgprocess is ref counted, so the existing dxgprocess objects is used for a process, which opens the device object multiple time. dxgprocess is destroyed when the device object is released.

A corresponding process object is created on the host for every dxgprocess object in the guest. Added a VM bus message to create and destroy the host side of a dxgprocess object.

Implement the handle manager, which manages d3dkmthandle handles for the internal process objects.

---
 drivers/hv/dxgkrnl/dxgkrnl.h    |  39 ++-
 drivers/hv/dxgkrnl/dxgmodule.c  |  67 +++-
 drivers/hv/dxgkrnl/dxgprocess.c |  80 +++++
 drivers/hv/dxgkrnl/dxgvmbus.c   |  79 +++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |   1 +
 drivers/hv/dxgkrnl/hmgr.c       | 543 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/hmgr.h       |  37 +++
 drivers/hv/dxgkrnl/ioctl.c      |  70 ++++
 drivers/hv/dxgkrnl/misc.h       |   1 -
 9 files changed, 914 insertions(+), 3 deletions(-)
drivers/hv/dxgkrnl/dxgkrnl.h +38 -1
index 15208328cb71..61512463baa4 100644
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/hyperv.h>
 
+struct dxgprocess;
 struct dxgadapter;
 
 #include "misc.h"
@@ -138,10 +139,44 @@ struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel(void);
 int dxgglobal_acquire_channel_lock(void);
 void dxgglobal_release_channel_lock(void);
 
+/*
+ * 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;
+	struct task_struct	*process;
+	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;
 };
 
+struct dxgprocess *dxgprocess_create(void);
+void dxgprocess_destroy(struct dxgprocess *process);
+void dxgprocess_release(struct kref *refcount);
+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);
+
 enum dxgadapter_state {
 	DXGADAPTER_STATE_ACTIVE		= 0,
 	DXGADAPTER_STATE_STOPPED	= 1,
@@ -211,6 +246,8 @@ static inline void guid_to_luid(guid_t *guid, struct winluid *luid)
 void dxgvmb_initialize(void);
 int dxgvmb_send_set_iospace_region(u64 start, u64 len,
 				   struct vmbus_gpadl *shared_mem_gpadl);
+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);
drivers/hv/dxgkrnl/dxgmodule.c +66 -1

89 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgprocess.c +80 -0

83 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.c +79 -0

85 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.h +1 -0
index 93cce587158b..5b455618a2a2 100644
@@ -14,6 +14,7 @@
 #ifndef _DXGVMBUS_H
 #define _DXGVMBUS_H
 
+struct dxgprocess;
 struct dxgadapter;
 
 #define DXG_MAX_VM_BUS_PACKET_SIZE	(1024 * 128)
drivers/hv/dxgkrnl/hmgr.c +543 -0

546 lines not on this page · raw message

drivers/hv/dxgkrnl/hmgr.h +37 -0
index b8b8f3ae5939..9ce4f536bf29 100644
@@ -72,4 +72,41 @@ enum hmgrentry_type {
 	HMGRENTRY_TYPE_MONITOREDFENCE	= 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 *object,
+				     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_type 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
drivers/hv/dxgkrnl/ioctl.c +70 -0

73 lines not on this page · raw message

drivers/hv/dxgkrnl/misc.h +0 -1
index 1ff0c0e28332..433b59d3eb23 100644
@@ -31,7 +31,6 @@ extern const struct d3dkmthandle zerohandle;
  * table_lock
  * core_lock
  * device_lock
- * process->process_mutex
  * adapter_list_lock
  * device_mutex
  */
Signature · 1 line
2.35.1
#12 lore raw

PATCH v2 3/24 drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects

In reply to Iouri Tarassov

Implement IOCTLs to enumerate and open dxgadapter objects:
LX_DXENUMADAPTERS2(D3DKMTEnumAdapters2) LX_DXENUMADAPTERS3(D3DKMTEnumAdapters2)

Implement IOCTLS to open adapter by LUID and to close adapter handle:
LX_DXOPENADAPTERFROMLUID(D3DKMTOpenAdapterFromLuid), LX_DXCLOSEADAPTER(D3DKMTCloseAdapter).

Impllement IOCTL to query dxgadapter information:
LX_DXQUERYADAPTERINFO.(D3DKMTQueryAdapterInfo).

When a dxgadapter is enumerated, a process handle (d3dkmthandle) is created in the current process and returned to the caller. The caller is responsible to close the adapter when it is not longer used by calling D3DKMTCloseAdapter.

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.

---
 drivers/hv/dxgkrnl/dxgadapter.c |  77 ++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  49 ++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  12 +
 drivers/hv/dxgkrnl/dxgprocess.c | 166 +++++++++++++
 drivers/hv/dxgkrnl/dxgvmbus.c   |  82 +++++++
 drivers/hv/dxgkrnl/ioctl.c      | 412 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/misc.h       |   1 +
 7 files changed, 799 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +77 -0
index e0a6fea00bd5..2c7823713547 100644
@@ -102,6 +102,7 @@ void dxgadapter_start(struct dxgadapter *adapter)
 
 void dxgadapter_stop(struct dxgadapter *adapter)
 {
+	struct dxgprocess_adapter *entry;
 	bool adapter_stopped = false;
 
 	down_write(&adapter->core_lock);
@@ -114,6 +115,15 @@ void dxgadapter_stop(struct dxgadapter *adapter)
 	if (adapter_stopped)
 		return;
 
+	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) == 0) {
 		dxgvmb_send_close_adapter(adapter);
 		dxgadapter_release_lock_exclusive(adapter);
@@ -137,6 +147,24 @@ bool dxgadapter_is_active(struct dxgadapter *adapter)
 	return adapter->adapter_state == DXGADAPTER_STATE_ACTIVE;
 }
 
+/* Protected by dxgglobal_acquire_process_adapter_lock */
+void dxgadapter_add_process(struct dxgadapter *adapter,
+			    struct dxgprocess_adapter *process_info)
+{
+	pr_debug("%s %p %p", __func__, adapter, process_info);
+	list_add_tail(&process_info->adapter_process_list_entry,
+		      &adapter->adapter_process_list_head);
+}
+
+void dxgadapter_remove_process(struct dxgprocess_adapter *process_info)
+{
+	pr_debug("%s %p %p", __func__,
+		    process_info->adapter, process_info);
+	list_del(&process_info->adapter_process_list_entry);
+	process_info->adapter_process_list_entry.next = NULL;
+	process_info->adapter_process_list_entry.prev = NULL;
+}
+
 int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter)
 {
 	down_write(&adapter->core_lock);
@@ -170,3 +198,52 @@ void dxgadapter_release_lock_shared(struct dxgadapter *adapter)
 {
 	up_read(&adapter->core_lock);
 }
+
+struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
+						     struct dxgadapter *adapter)
+{
+	struct dxgprocess_adapter *adapter_info;
+
+	adapter_info = vzalloc(sizeof(*adapter_info));
+	if (adapter_info) {
+		if (kref_get_unless_zero(&adapter->adapter_kref) == 0) {
+			pr_err("failed to acquire adapter reference");
+			goto cleanup;
+		}
+		adapter_info->adapter = adapter;
+		adapter_info->process = process;
+		adapter_info->refcount = 1;
+		list_add_tail(&adapter_info->process_adapter_list_entry,
+			      &process->process_adapter_list_head);
+		dxgadapter_add_process(adapter, adapter_info);
+	}
+	return adapter_info;
+cleanup:
+	if (adapter_info)
+		vfree(adapter_info);
+	return NULL;
+}
+
+void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info)
+{
+}
+
+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);
+	vfree(adapter_info);
+}
+
+/*
+ * Must be called when dxgglobal::process_adapter_mutex is held
+ */
+void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter_info)
+{
+	pr_debug("%s %p %d",
+		    __func__, adapter_info, adapter_info->refcount);
+	adapter_info->refcount--;
+	if (adapter_info->refcount == 0)
+		dxgprocess_adapter_destroy(adapter_info);
+}
drivers/hv/dxgkrnl/dxgkrnl.h +49 -0

97 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgmodule.c +12 -0
index 64ac35e1863b..fafe0b6a6389 100644
@@ -124,6 +124,16 @@ static struct dxgadapter *find_adapter(struct winluid *luid)
 	return adapter;
 }
 
+void dxgglobal_acquire_process_adapter_lock(void)
+{
+	mutex_lock(&dxgglobal->process_adapter_mutex);
+}
+
+void dxgglobal_release_process_adapter_lock(void)
+{
+	mutex_unlock(&dxgglobal->process_adapter_mutex);
+}
+
 /*
  * Creates a new dxgadapter object, which represents a virtual GPU, projected
  * by the host.
@@ -147,6 +157,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
 	kref_init(&adapter->adapter_kref);
 	init_rwsem(&adapter->core_lock);
 
+	INIT_LIST_HEAD(&adapter->adapter_process_list_head);
 	adapter->pci_dev = dev;
 	guid_to_luid(guid, &adapter->luid);
 
@@ -721,6 +732,7 @@ static int dxgglobal_create(void)
 	INIT_LIST_HEAD(&dxgglobal->plisthead);
 	mutex_init(&dxgglobal->plistmutex);
 	mutex_init(&dxgglobal->device_mutex);
+	mutex_init(&dxgglobal->process_adapter_mutex);
 
 	INIT_LIST_HEAD(&dxgglobal->thread_info_list_head);
 	mutex_init(&dxgglobal->thread_info_mutex);
drivers/hv/dxgkrnl/dxgprocess.c +166 -0

184 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.c +82 -0

85 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +412 -0

422 lines not on this page · raw message

drivers/hv/dxgkrnl/misc.h +1 -0
index 433b59d3eb23..d00e7cc00470 100644
@@ -31,6 +31,7 @@ extern const struct d3dkmthandle zerohandle;
  * table_lock
  * core_lock
  * device_lock
+ * process_adapter_mutex
  * adapter_list_lock
  * device_mutex
  */
Signature · 1 line
2.35.1
#13 lore raw

PATCH v2 4/24 drivers: hv: dxgkrnl: Creation of dxgdevice

In reply to Iouri Tarassov

A dxgdevice object represents a container of GPU allocations, GPU sync objects, GPU contexts, etc. It belongs to a dxgadapter object.

---
 drivers/hv/dxgkrnl/dxgadapter.c | 183 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  52 +++++++++
 drivers/hv/dxgkrnl/dxgprocess.c |  43 ++++++++
 drivers/hv/dxgkrnl/dxgvmbus.c   |  54 ++++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 134 +++++++++++++++++++++++
 drivers/hv/dxgkrnl/misc.h       |   1 +
 6 files changed, 467 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +183 -0
index 2c7823713547..c7e1dc55de49 100644
@@ -199,6 +199,120 @@ void dxgadapter_release_lock_shared(struct dxgadapter *adapter)
 	up_read(&adapter->core_lock);
 }
 
+struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
+				   struct dxgprocess *process)
+{
+	struct dxgdevice *device = vzalloc(sizeof(struct dxgdevice));
+	int ret;
+
+	if (device) {
+		kref_init(&device->device_kref);
+		device->adapter = adapter;
+		device->process = process;
+		kref_get(&adapter->adapter_kref);
+		init_rwsem(&device->device_lock);
+		INIT_LIST_HEAD(&device->pqueue_list_head);
+		device->object_state = DXGOBJECTSTATE_CREATED;
+		device->execution_state = _D3DKMT_DEVICEEXECUTION_ACTIVE;
+
+		ret = dxgprocess_adapter_add_device(process, adapter, device);
+		if (ret < 0) {
+			kref_put(&device->device_kref, dxgdevice_release);
+			device = NULL;
+		}
+	}
+	return device;
+}
+
+void dxgdevice_stop(struct dxgdevice *device)
+{
+}
+
+void dxgdevice_mark_destroyed(struct dxgdevice *device)
+{
+	down_write(&device->device_lock);
+	device->object_state = DXGOBJECTSTATE_DESTROYED;
+	up_write(&device->device_lock);
+}
+
+void dxgdevice_destroy(struct dxgdevice *device)
+{
+	struct dxgprocess *process = device->process;
+	struct dxgadapter *adapter = device->adapter;
+	struct d3dkmthandle device_handle = {};
+
+	pr_debug("%s: %p\n", __func__, device);
+
+	down_write(&device->device_lock);
+
+	if (device->object_state != DXGOBJECTSTATE_ACTIVE)
+		goto cleanup;
+
+	device->object_state = DXGOBJECTSTATE_DESTROYED;
+
+	dxgdevice_stop(device);
+
+	/* Guest handles need to be released before the host handles */
+	hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+	if (device->handle_valid) {
+		hmgrtable_free_handle(&process->handle_table,
+				      HMGRENTRY_TYPE_DXGDEVICE, device->handle);
+		device_handle = device->handle;
+		device->handle_valid = 0;
+	}
+	hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+	if (device_handle.v) {
+		up_write(&device->device_lock);
+		if (dxgadapter_acquire_lock_shared(adapter) == 0) {
+			dxgvmb_send_destroy_device(adapter, process,
+						   device_handle);
+			dxgadapter_release_lock_shared(adapter);
+		}
+		down_write(&device->device_lock);
+	}
+
+cleanup:
+
+	if (device->adapter) {
+		dxgprocess_adapter_remove_device(device);
+		kref_put(&device->adapter->adapter_kref, dxgadapter_release);
+	}
+
+	up_write(&device->device_lock);
+
+	kref_put(&device->device_kref, dxgdevice_release);
+	pr_debug("dxgdevice_destroy_end\n");
+}
+
+int dxgdevice_acquire_lock_shared(struct dxgdevice *device)
+{
+	down_read(&device->device_lock);
+	if (!dxgdevice_is_active(device)) {
+		up_read(&device->device_lock);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+void dxgdevice_release_lock_shared(struct dxgdevice *device)
+{
+	up_read(&device->device_lock);
+}
+
+bool dxgdevice_is_active(struct dxgdevice *device)
+{
+	return device->object_state == DXGOBJECTSTATE_ACTIVE;
+}
+
+void dxgdevice_release(struct kref *refcount)
+{
+	struct dxgdevice *device;
+
+	device = container_of(refcount, struct dxgdevice, device_kref);
+	vfree(device);
+}
+
 struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
 						     struct dxgadapter *adapter)
 {
@@ -213,6 +327,8 @@ struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
 		adapter_info->adapter = adapter;
 		adapter_info->process = process;
 		adapter_info->refcount = 1;
+		mutex_init(&adapter_info->device_list_mutex);
+		INIT_LIST_HEAD(&adapter_info->device_list_head);
 		list_add_tail(&adapter_info->process_adapter_list_entry,
 			      &process->process_adapter_list_head);
 		dxgadapter_add_process(adapter, adapter_info);
@@ -226,10 +342,32 @@ struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
 
 void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info)
 {
+	struct dxgdevice *device;
+
+	mutex_lock(&adapter_info->device_list_mutex);
+	list_for_each_entry(device, &adapter_info->device_list_head,
+			    device_list_entry) {
+		dxgdevice_stop(device);
+	}
+	mutex_unlock(&adapter_info->device_list_mutex);
 }
 
 void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info)
 {
+	struct dxgdevice *device;
+
+	mutex_lock(&adapter_info->device_list_mutex);
+	while (!list_empty(&adapter_info->device_list_head)) {
+		device = list_first_entry(&adapter_info->device_list_head,
+					  struct dxgdevice, device_list_entry);
+		list_del(&device->device_list_entry);
+		device->device_list_entry.next = NULL;
+		mutex_unlock(&adapter_info->device_list_mutex);
+		dxgdevice_destroy(device);
+		mutex_lock(&adapter_info->device_list_mutex);
+	}
+	mutex_unlock(&adapter_info->device_list_mutex);
+
 	dxgadapter_remove_process(adapter_info);
 	kref_put(&adapter_info->adapter->adapter_kref, dxgadapter_release);
 	list_del(&adapter_info->process_adapter_list_entry);
@@ -247,3 +385,48 @@ void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter_info)
 	if (adapter_info->refcount == 0)
 		dxgprocess_adapter_destroy(adapter_info);
 }
+
+int dxgprocess_adapter_add_device(struct dxgprocess *process,
+				  struct dxgadapter *adapter,
+				  struct dxgdevice *device)
+{
+	struct dxgprocess_adapter *entry;
+	struct dxgprocess_adapter *adapter_info = NULL;
+	int ret = 0;
+
+	dxgglobal_acquire_process_adapter_lock();
+
+	list_for_each_entry(entry, &process->process_adapter_list_head,
+			    process_adapter_list_entry) {
+		if (entry->adapter == adapter) {
+			adapter_info = entry;
+			break;
+		}
+	}
+	if (adapter_info == NULL) {
+		pr_err("failed to find process adapter info\n");
+		ret = -EINVAL;
+		goto cleanup;
+	}
+	mutex_lock(&adapter_info->device_list_mutex);
+	list_add_tail(&device->device_list_entry,
+		      &adapter_info->device_list_head);
+	device->adapter_info = adapter_info;
+	mutex_unlock(&adapter_info->device_list_mutex);
+
+cleanup:
+
+	dxgglobal_release_process_adapter_lock();
+	return ret;
+}
+
+void dxgprocess_adapter_remove_device(struct dxgdevice *device)
+{
+	pr_debug("%s %p\n", __func__, device);
+	mutex_lock(&device->adapter_info->device_list_mutex);
+	if (device->device_list_entry.next) {
+		list_del(&device->device_list_entry);
+		device->device_list_entry.next = NULL;
+	}
+	mutex_unlock(&device->adapter_info->device_list_mutex);
+}
drivers/hv/dxgkrnl/dxgkrnl.h +52 -0

94 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgprocess.c +43 -0

49 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.c +54 -0

60 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +134 -0

152 lines not on this page · raw message

drivers/hv/dxgkrnl/misc.h +1 -0
index d00e7cc00470..8948f48ec9dc 100644
@@ -25,6 +25,7 @@ extern const struct d3dkmthandle zerohandle;
  * The higher enum value, the higher is the lock order.
  * When a lower lock ois held, the higher lock should not be acquired.
  *
+ * device_list_mutex
  * channel_lock
  * fd_mutex
  * plistmutex
Signature · 1 line
2.35.1
#14 lore raw

PATCH v2 5/24 drivers: hv: dxgkrnl: Creation of dxgcontext objects

In reply to Iouri Tarassov

Implement ioctls for dxgcontext creation/destruction:
LX_DXCREATECONTEXTVIRTUAL(D3DKMTCreateContextVirtual), LX_DXDESTROYCONTEXT(D3DKMTDestroyContext)

A dxgcontext object represents a GPU execution thread. GPU DMA buffers and synchronization operations are submitted for execution to a GPU context. GPU contexts belong to a dxgdevice object.

---
 drivers/hv/dxgkrnl/dxgadapter.c | 102 +++++++++++++++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  38 +++++++
 drivers/hv/dxgkrnl/dxgprocess.c |   4 +
 drivers/hv/dxgkrnl/dxgvmbus.c   |  99 ++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 172 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/misc.h       |   1 +
 6 files changed, 416 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +102 -0
index c7e1dc55de49..9cdc81d4db4a 100644
@@ -210,7 +210,9 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
 		device->adapter = adapter;
 		device->process = 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 = DXGOBJECTSTATE_CREATED;
 		device->execution_state = _D3DKMT_DEVICEEXECUTION_ACTIVE;
@@ -252,6 +254,20 @@ void dxgdevice_destroy(struct dxgdevice *device)
 
 	dxgdevice_stop(device);
 
+	{
+		struct dxgcontext *context;
+		struct dxgcontext *tmp;
+
+		pr_debug("destroying contexts\n");
+		dxgdevice_acquire_context_list_lock(device);
+		list_for_each_entry_safe(context, tmp,
+					 &device->context_list_head,
+					 context_list_entry) {
+			dxgcontext_destroy(process, context);
+		}
+		dxgdevice_release_context_list_lock(device);
+	}
+
 	/* Guest handles need to be released before the host handles */
 	hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
 	if (device->handle_valid) {
@@ -305,6 +321,32 @@ bool dxgdevice_is_active(struct dxgdevice *device)
 	return device->object_state == DXGOBJECTSTATE_ACTIVE;
 }
 
+void dxgdevice_acquire_context_list_lock(struct dxgdevice *device)
+{
+	down_write(&device->context_list_lock);
+}
+
+void dxgdevice_release_context_list_lock(struct dxgdevice *device)
+{
+	up_write(&device->context_list_lock);
+}
+
+void dxgdevice_add_context(struct dxgdevice *device, struct dxgcontext *context)
+{
+	down_write(&device->context_list_lock);
+	list_add_tail(&context->context_list_entry, &device->context_list_head);
+	up_write(&device->context_list_lock);
+}
+
+void dxgdevice_remove_context(struct dxgdevice *device,
+			      struct dxgcontext *context)
+{
+	if (context->context_list_entry.next) {
+		list_del(&context->context_list_entry);
+		context->context_list_entry.next = NULL;
+	}
+}
+
 void dxgdevice_release(struct kref *refcount)
 {
 	struct dxgdevice *device;
@@ -313,6 +355,66 @@ void dxgdevice_release(struct kref *refcount)
 	vfree(device);
 }
 
+struct dxgcontext *dxgcontext_create(struct dxgdevice *device)
+{
+	struct dxgcontext *context = vzalloc(sizeof(struct dxgcontext));
+
+	if (context) {
+		kref_init(&context->context_kref);
+		context->device = device;
+		context->process = device->process;
+		context->device_handle = device->handle;
+		kref_get(&device->device_kref);
+		INIT_LIST_HEAD(&context->hwqueue_list_head);
+		init_rwsem(&context->hwqueue_list_lock);
+		dxgdevice_add_context(device, context);
+		context->object_state = DXGOBJECTSTATE_ACTIVE;
+	}
+	return context;
+}
+
+/*
+ * Called when the device context list lock is held
+ */
+void dxgcontext_destroy(struct dxgprocess *process, struct dxgcontext *context)
+{
+	pr_debug("%s %p\n", __func__, context);
+	context->object_state = DXGOBJECTSTATE_DESTROYED;
+	if (context->device) {
+		if (context->handle.v) {
+			hmgrtable_free_handle_safe(&process->handle_table,
+						   HMGRENTRY_TYPE_DXGCONTEXT,
+						   context->handle);
+		}
+		dxgdevice_remove_context(context->device, context);
+		kref_put(&context->device->device_kref, dxgdevice_release);
+	}
+	kref_put(&context->context_kref, dxgcontext_release);
+}
+
+void dxgcontext_destroy_safe(struct dxgprocess *process,
+			     struct dxgcontext *context)
+{
+	struct dxgdevice *device = context->device;
+
+	dxgdevice_acquire_context_list_lock(device);
+	dxgcontext_destroy(process, context);
+	dxgdevice_release_context_list_lock(device);
+}
+
+bool dxgcontext_is_active(struct dxgcontext *context)
+{
+	return context->object_state == DXGOBJECTSTATE_ACTIVE;
+}
+
+void dxgcontext_release(struct kref *refcount)
+{
+	struct dxgcontext *context;
+
+	context = container_of(refcount, struct dxgcontext, context_kref);
+	vfree(context);
+}
+
 struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
 						     struct dxgadapter *adapter)
 {
drivers/hv/dxgkrnl/dxgkrnl.h +38 -0
index e0a433c36a06..b4ca479cdd1a 100644
@@ -30,6 +30,7 @@
 struct dxgprocess;
 struct dxgadapter;
 struct dxgdevice;
+struct dxgcontext;
 
 #include "misc.h"
 #include "hmgr.h"
@@ -281,6 +282,7 @@ void dxgadapter_remove_process(struct dxgprocess_adapter *process_info);
 /*
  * The object represent the device object.
  * The following objects take reference on the device
+ * - dxgcontext
  * - device handle (struct d3dkmthandle)
  */
 struct dxgdevice {
@@ -294,6 +296,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;
@@ -308,7 +312,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 *ctx);
 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);
 
 void init_ioctls(void);
 long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2);
@@ -349,6 +379,14 @@ struct d3dkmthandle dxgvmb_send_create_device(struct dxgadapter *adapter,
 int dxgvmb_send_destroy_device(struct dxgadapter *adapter,
 			       struct dxgprocess *process,
 			       struct d3dkmthandle h);
+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);
drivers/hv/dxgkrnl/dxgprocess.c +4 -0
index 734585689213..1e6500e12a22 100644
@@ -258,6 +258,10 @@ struct dxgdevice *dxgprocess_device_by_object_handle(struct dxgprocess *process,
 		case HMGRENTRY_TYPE_DXGDEVICE:
 			device = obj;
 			break;
+		case HMGRENTRY_TYPE_DXGCONTEXT:
+			device_handle =
+			    ((struct dxgcontext *)obj)->device_handle;
+			break;
 		default:
 			pr_err("invalid handle type: %d\n", t);
 			break;
drivers/hv/dxgkrnl/dxgvmbus.c +99 -0

105 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +172 -0

184 lines not on this page · raw message

drivers/hv/dxgkrnl/misc.h +1 -0
index 8948f48ec9dc..8f7b37049308 100644
@@ -30,6 +30,7 @@ extern const struct d3dkmthandle zerohandle;
  * fd_mutex
  * plistmutex
  * table_lock
+ * context_list_lock
  * core_lock
  * device_lock
  * process_adapter_mutex
Signature · 1 line
2.35.1
#15 lore raw

PATCH v2 6/24 drivers: hv: dxgkrnl: Creation of GPU allocations and resources

In reply to Iouri Tarassov

Implemented ioctls to create and destroy GPU allocations and resources:
LX_DXCREATEALLOCATION(D3DKMTCreateAllocation), LX_DXDESTROYALLOCATION2(D3DKMTDestroyAllocation2).

GPU allocations (dxgallocation objects) represent memory allocation, which could be accessible by GPU. Allocations can be created around existing system memory (provided by the application) or memory, allocated by dxgkrnl.

GPU resources (dxgresource objects) represent containers ofr GPU allocations. Allocations could be dynamically added, removed from a resource.

Each allocation/resource has associated driver private data, which is provided during creation.

---
 drivers/hv/dxgkrnl/dxgadapter.c | 274 ++++++++++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    | 109 ++++++
 drivers/hv/dxgkrnl/dxgmodule.c  |   1 +
 drivers/hv/dxgkrnl/dxgvmbus.c   | 645 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 637 +++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/misc.h       |   3 +
 6 files changed, 1669 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +274 -0
index 9cdc81d4db4a..3f51456272cc 100644
@@ -211,8 +211,11 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
 		device->process = process;
 		kref_get(&adapter->adapter_kref);
 		INIT_LIST_HEAD(&device->context_list_head);
+		INIT_LIST_HEAD(&device->alloc_list_head);
+		INIT_LIST_HEAD(&device->resource_list_head);
 		init_rwsem(&device->device_lock);
 		init_rwsem(&device->context_list_lock);
+		init_rwsem(&device->alloc_list_lock);
 		INIT_LIST_HEAD(&device->pqueue_list_head);
 		device->object_state = DXGOBJECTSTATE_CREATED;
 		device->execution_state = _D3DKMT_DEVICEEXECUTION_ACTIVE;
@@ -228,6 +231,16 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
 
 void dxgdevice_stop(struct dxgdevice *device)
 {
+	struct dxgallocation *alloc;
+
+	pr_debug("%s: %p", __func__, device);
+	dxgdevice_acquire_alloc_list_lock(device);
+	list_for_each_entry(alloc, &device->alloc_list_head, alloc_list_entry) {
+		dxgallocation_stop(alloc);
+	}
+	dxgdevice_release_alloc_list_lock(device);
+
+	pr_debug("%s: end %p\n", __func__, device);
 }
 
 void dxgdevice_mark_destroyed(struct dxgdevice *device)
@@ -254,6 +267,33 @@ void dxgdevice_destroy(struct dxgdevice *device)
 
 	dxgdevice_stop(device);
 
+	dxgdevice_acquire_alloc_list_lock(device);
+
+	{
+		struct dxgallocation *alloc;
+		struct dxgallocation *tmp;
+
+		pr_debug("destroying allocations\n");
+		list_for_each_entry_safe(alloc, tmp, &device->alloc_list_head,
+					 alloc_list_entry) {
+			dxgallocation_destroy(alloc);
+		}
+	}
+
+	{
+		struct dxgresource *resource;
+		struct dxgresource *tmp;
+
+		pr_debug("destroying resources\n");
+		list_for_each_entry_safe(resource, tmp,
+					 &device->resource_list_head,
+					 resource_list_entry) {
+			dxgresource_destroy(resource);
+		}
+	}
+
+	dxgdevice_release_alloc_list_lock(device);
+
 	{
 		struct dxgcontext *context;
 		struct dxgcontext *tmp;
@@ -331,6 +371,26 @@ void dxgdevice_release_context_list_lock(struct dxgdevice *device)
 	up_write(&device->context_list_lock);
 }
 
+void dxgdevice_acquire_alloc_list_lock(struct dxgdevice *device)
+{
+	down_write(&device->alloc_list_lock);
+}
+
+void dxgdevice_release_alloc_list_lock(struct dxgdevice *device)
+{
+	up_write(&device->alloc_list_lock);
+}
+
+void dxgdevice_acquire_alloc_list_lock_shared(struct dxgdevice *device)
+{
+	down_read(&device->alloc_list_lock);
+}
+
+void dxgdevice_release_alloc_list_lock_shared(struct dxgdevice *device)
+{
+	up_read(&device->alloc_list_lock);
+}
+
 void dxgdevice_add_context(struct dxgdevice *device, struct dxgcontext *context)
 {
 	down_write(&device->context_list_lock);
@@ -347,6 +407,160 @@ void dxgdevice_remove_context(struct dxgdevice *device,
 	}
 }
 
+void dxgdevice_add_alloc(struct dxgdevice *device, struct dxgallocation *alloc)
+{
+	dxgdevice_acquire_alloc_list_lock(device);
+	list_add_tail(&alloc->alloc_list_entry, &device->alloc_list_head);
+	kref_get(&device->device_kref);
+	alloc->owner.device = device;
+	dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_alloc(struct dxgdevice *device,
+			    struct dxgallocation *alloc)
+{
+	if (alloc->alloc_list_entry.next) {
+		list_del(&alloc->alloc_list_entry);
+		alloc->alloc_list_entry.next = NULL;
+		kref_put(&device->device_kref, dxgdevice_release);
+	}
+}
+
+void dxgdevice_remove_alloc_safe(struct dxgdevice *device,
+				 struct dxgallocation *alloc)
+{
+	dxgdevice_acquire_alloc_list_lock(device);
+	dxgdevice_remove_alloc(device, alloc);
+	dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_add_resource(struct dxgdevice *device, struct dxgresource *res)
+{
+	dxgdevice_acquire_alloc_list_lock(device);
+	list_add_tail(&res->resource_list_entry, &device->resource_list_head);
+	kref_get(&device->device_kref);
+	dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_resource(struct dxgdevice *device,
+			       struct dxgresource *res)
+{
+	if (res->resource_list_entry.next) {
+		list_del(&res->resource_list_entry);
+		res->resource_list_entry.next = NULL;
+		kref_put(&device->device_kref, dxgdevice_release);
+	}
+}
+
+struct dxgresource *dxgresource_create(struct dxgdevice *device)
+{
+	struct dxgresource *resource = vzalloc(sizeof(struct dxgresource));
+
+	if (resource) {
+		kref_init(&resource->resource_kref);
+		resource->device = device;
+		resource->process = device->process;
+		resource->object_state = DXGOBJECTSTATE_ACTIVE;
+		mutex_init(&resource->resource_mutex);
+		INIT_LIST_HEAD(&resource->alloc_list_head);
+		dxgdevice_add_resource(device, resource);
+	}
+	return resource;
+}
+
+void dxgresource_free_handle(struct dxgresource *resource)
+{
+	struct dxgallocation *alloc;
+	struct dxgprocess *process;
+
+	if (resource->handle_valid) {
+		process = resource->device->process;
+		hmgrtable_free_handle_safe(&process->handle_table,
+					   HMGRENTRY_TYPE_DXGRESOURCE,
+					   resource->handle);
+		resource->handle_valid = 0;
+	}
+	list_for_each_entry(alloc, &resource->alloc_list_head,
+			    alloc_list_entry) {
+		dxgallocation_free_handle(alloc);
+	}
+}
+
+void dxgresource_destroy(struct dxgresource *resource)
+{
+	/* device->alloc_list_lock is held */
+	struct dxgallocation *alloc;
+	struct dxgallocation *tmp;
+	struct d3dkmt_destroyallocation2 args = { };
+	int destroyed = test_and_set_bit(0, &resource->flags);
+	struct dxgdevice *device = resource->device;
+
+	if (!destroyed) {
+		dxgresource_free_handle(resource);
+		if (resource->handle.v) {
+			args.device = device->handle;
+			args.resource = resource->handle;
+			dxgvmb_send_destroy_allocation(device->process,
+						       device, &args, NULL);
+			resource->handle.v = 0;
+		}
+		list_for_each_entry_safe(alloc, tmp, &resource->alloc_list_head,
+					 alloc_list_entry) {
+			dxgallocation_destroy(alloc);
+		}
+		dxgdevice_remove_resource(device, resource);
+	}
+	kref_put(&resource->resource_kref, dxgresource_release);
+}
+
+void dxgresource_release(struct kref *refcount)
+{
+	struct dxgresource *resource;
+
+	resource = container_of(refcount, struct dxgresource, resource_kref);
+	vfree(resource);
+}
+
+bool dxgresource_is_active(struct dxgresource *resource)
+{
+	return resource->object_state == DXGOBJECTSTATE_ACTIVE;
+}
+
+int dxgresource_add_alloc(struct dxgresource *resource,
+				      struct dxgallocation *alloc)
+{
+	int ret = -ENODEV;
+	struct dxgdevice *device = resource->device;
+
+	dxgdevice_acquire_alloc_list_lock(device);
+	if (dxgresource_is_active(resource)) {
+		list_add_tail(&alloc->alloc_list_entry,
+			      &resource->alloc_list_head);
+		alloc->owner.resource = resource;
+		ret = 0;
+	}
+	alloc->resource_owner = 1;
+	dxgdevice_release_alloc_list_lock(device);
+	return ret;
+}
+
+void dxgresource_remove_alloc(struct dxgresource *resource,
+			      struct dxgallocation *alloc)
+{
+	if (alloc->alloc_list_entry.next) {
+		list_del(&alloc->alloc_list_entry);
+		alloc->alloc_list_entry.next = NULL;
+	}
+}
+
+void dxgresource_remove_alloc_safe(struct dxgresource *resource,
+				   struct dxgallocation *alloc)
+{
+	dxgdevice_acquire_alloc_list_lock(resource->device);
+	dxgresource_remove_alloc(resource, alloc);
+	dxgdevice_release_alloc_list_lock(resource->device);
+}
+
 void dxgdevice_release(struct kref *refcount)
 {
 	struct dxgdevice *device;
@@ -415,6 +629,66 @@ void dxgcontext_release(struct kref *refcount)
 	vfree(context);
 }
 
+struct dxgallocation *dxgallocation_create(struct dxgprocess *process)
+{
+	struct dxgallocation *alloc = vzalloc(sizeof(struct dxgallocation));
+
+	if (alloc)
+		alloc->process = process;
+	return alloc;
+}
+
+void dxgallocation_stop(struct dxgallocation *alloc)
+{
+	if (alloc->pages) {
+		release_pages(alloc->pages, alloc->num_pages);
+		vfree(alloc->pages);
+		alloc->pages = NULL;
+	}
+}
+
+void dxgallocation_free_handle(struct dxgallocation *alloc)
+{
+	dxgprocess_ht_lock_exclusive_down(alloc->process);
+	if (alloc->handle_valid) {
+		hmgrtable_free_handle(&alloc->process->handle_table,
+				      HMGRENTRY_TYPE_DXGALLOCATION,
+				      alloc->alloc_handle);
+		alloc->handle_valid = 0;
+	}
+	dxgprocess_ht_lock_exclusive_up(alloc->process);
+}
+
+void dxgallocation_destroy(struct dxgallocation *alloc)
+{
+	struct dxgprocess *process = alloc->process;
+	struct d3dkmt_destroyallocation2 args = { };
+
+	dxgallocation_stop(alloc);
+	if (alloc->resource_owner)
+		dxgresource_remove_alloc(alloc->owner.resource, alloc);
+	else if (alloc->owner.device)
+		dxgdevice_remove_alloc(alloc->owner.device, alloc);
+	dxgallocation_free_handle(alloc);
+	if (alloc->alloc_handle.v && !alloc->resource_owner) {
+		args.device = alloc->owner.device->handle;
+		args.alloc_count = 1;
+		dxgvmb_send_destroy_allocation(process,
+					       alloc->owner.device,
+					       &args, &alloc->alloc_handle);
+	}
+	if (alloc->gpadl.gpadl_handle) {
+		pr_debug("Teardown gpadl %d",
+			alloc->gpadl.gpadl_handle);
+		vmbus_teardown_gpadl(dxgglobal_get_vmbus(), &alloc->gpadl);
+		pr_debug("Teardown gpadl end");
+		alloc->gpadl.gpadl_handle = 0;
+	}
+	if (alloc->priv_drv_data)
+		vfree(alloc->priv_drv_data);
+	vfree(alloc);
+}
+
 struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
 						     struct dxgadapter *adapter)
 {
drivers/hv/dxgkrnl/dxgkrnl.h +109 -0

151 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgmodule.c +1 -0
index fafe0b6a6389..d865ac45f89d 100644
@@ -158,6 +158,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
 	init_rwsem(&adapter->core_lock);
 
 	INIT_LIST_HEAD(&adapter->adapter_process_list_head);
+	init_rwsem(&adapter->shared_resource_list_lock);
 	adapter->pci_dev = dev;
 	guid_to_luid(guid, &adapter->luid);
 
drivers/hv/dxgkrnl/dxgvmbus.c +645 -0

657 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +637 -0

651 lines not on this page · raw message

drivers/hv/dxgkrnl/misc.h +3 -0
index 8f7b37049308..41abdc504bc2 100644
@@ -31,6 +31,9 @@ extern const struct d3dkmthandle zerohandle;
  * plistmutex
  * table_lock
  * context_list_lock
+ * alloc_list_lock
+ * resource_mutex
+ * shared_resource_list_lock
  * core_lock
  * device_lock
  * process_adapter_mutex
Signature · 1 line
2.35.1
#16 lore raw

PATCH v2 7/24 drivers: hv: dxgkrnl: Create and destroy GPU sync objects

In reply to Iouri Tarassov

GPU synchronization objects are used to synchornize GPU command execution between different execution contexts.

Implement ioctls to create and destroy sync objects:
LX_DXCREATESYNCHRONIZATIONOBJECT(D3DKMTCreateSynchronizationObject), LX_DXDESTROYSYNCHRONIZATIONOBJECT(D3DKMTDestroySynchronizationObject)

Monitored fence sync objects have a CPU virtual address 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

---
 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   | 199 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 130 +++++++++++++++++++++
 6 files changed, 610 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +184 -0
index 3f51456272cc..2a9a731c3352 100644
@@ -165,6 +165,24 @@ void dxgadapter_remove_process(struct dxgprocess_adapter *process_info)
 	process_info->adapter_process_list_entry.prev = NULL;
 }
 
+void dxgadapter_add_syncobj(struct dxgadapter *adapter,
+			    struct dxgsyncobject *object)
+{
+	down_write(&adapter->shared_resource_list_lock);
+	list_add_tail(&object->syncobj_list_entry, &adapter->syncobj_list_head);
+	up_write(&adapter->shared_resource_list_lock);
+}
+
+void dxgadapter_remove_syncobj(struct dxgsyncobject *object)
+{
+	down_write(&object->adapter->shared_resource_list_lock);
+	if (object->syncobj_list_entry.next) {
+		list_del(&object->syncobj_list_entry);
+		object->syncobj_list_entry.next = NULL;
+	}
+	up_write(&object->adapter->shared_resource_list_lock);
+}
+
 int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter)
 {
 	down_write(&adapter->core_lock);
@@ -217,6 +235,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
 		init_rwsem(&device->context_list_lock);
 		init_rwsem(&device->alloc_list_lock);
 		INIT_LIST_HEAD(&device->pqueue_list_head);
+		INIT_LIST_HEAD(&device->syncobj_list_head);
 		device->object_state = DXGOBJECTSTATE_CREATED;
 		device->execution_state = _D3DKMT_DEVICEEXECUTION_ACTIVE;
 
@@ -232,6 +251,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
 void dxgdevice_stop(struct dxgdevice *device)
 {
 	struct dxgallocation *alloc;
+	struct dxgsyncobject *syncobj;
 
 	pr_debug("%s: %p", __func__, device);
 	dxgdevice_acquire_alloc_list_lock(device);
@@ -240,6 +260,12 @@ void dxgdevice_stop(struct dxgdevice *device)
 	}
 	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);
 	pr_debug("%s: end %p\n", __func__, device);
 }
 
@@ -269,6 +295,20 @@ void dxgdevice_destroy(struct dxgdevice *device)
 
 	dxgdevice_acquire_alloc_list_lock(device);
 
+	while (!list_empty(&device->syncobj_list_head)) {
+		struct dxgsyncobject *syncobj =
+		    list_first_entry(&device->syncobj_list_head,
+				     struct dxgsyncobject,
+				     syncobj_list_entry);
+		list_del(&syncobj->syncobj_list_entry);
+		syncobj->syncobj_list_entry.next = NULL;
+		dxgdevice_release_alloc_list_lock(device);
+
+		dxgsyncobject_destroy(process, syncobj);
+
+		dxgdevice_acquire_alloc_list_lock(device);
+	}
+
 	{
 		struct dxgallocation *alloc;
 		struct dxgallocation *tmp;
@@ -569,6 +609,30 @@ void dxgdevice_release(struct kref *refcount)
 	vfree(device);
 }
 
+void dxgdevice_add_syncobj(struct dxgdevice *device,
+			   struct dxgsyncobject *syncobj)
+{
+	dxgdevice_acquire_alloc_list_lock(device);
+	list_add_tail(&syncobj->syncobj_list_entry, &device->syncobj_list_head);
+	kref_get(&syncobj->syncobj_kref);
+	dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_syncobj(struct dxgsyncobject *entry)
+{
+	struct dxgdevice *device = entry->device;
+
+	dxgdevice_acquire_alloc_list_lock(device);
+	if (entry->syncobj_list_entry.next) {
+		list_del(&entry->syncobj_list_entry);
+		entry->syncobj_list_entry.next = NULL;
+		kref_put(&entry->syncobj_kref, dxgsyncobject_release);
+	}
+	dxgdevice_release_alloc_list_lock(device);
+	kref_put(&device->device_kref, dxgdevice_release);
+	entry->device = NULL;
+}
+
 struct dxgcontext *dxgcontext_create(struct dxgdevice *device)
 {
 	struct dxgcontext *context = vzalloc(sizeof(struct dxgcontext));
@@ -806,3 +870,123 @@ void dxgprocess_adapter_remove_device(struct dxgdevice *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 = vzalloc(sizeof(*syncobj));
+	if (syncobj == NULL)
+		goto cleanup;
+	syncobj->type = type;
+	syncobj->process = process;
+	switch (type) {
+	case _D3DDDI_MONITORED_FENCE:
+	case _D3DDDI_PERIODIC_MONITORED_FENCE:
+		syncobj->monitored_fence = 1;
+		break;
+	default:
+		break;
+	}
+	if (flags.shared) {
+		syncobj->shared = 1;
+		if (!flags.nt_security_sharing) {
+			dev_err(dxgglobaldev,
+				"%s: nt_security_sharing must be set",
+				__func__);
+			goto cleanup;
+		}
+	}
+
+	kref_init(&syncobj->syncobj_kref);
+
+	if (syncobj->monitored_fence) {
+		syncobj->device = device;
+		syncobj->device_handle = device->handle;
+		kref_get(&device->device_kref);
+		dxgdevice_add_syncobj(device, syncobj);
+	} else {
+		dxgadapter_add_syncobj(adapter, syncobj);
+	}
+	syncobj->adapter = adapter;
+	kref_get(&adapter->adapter_kref);
+
+	pr_debug("%s 0x%p\n", __func__, syncobj);
+	return syncobj;
+cleanup:
+	if (syncobj)
+		vfree(syncobj);
+	return NULL;
+}
+
+void dxgsyncobject_destroy(struct dxgprocess *process,
+			   struct dxgsyncobject *syncobj)
+{
+	int destroyed;
+
+	pr_debug("%s 0x%p", __func__, syncobj);
+
+	dxgsyncobject_stop(syncobj);
+
+	destroyed = test_and_set_bit(0, &syncobj->flags);
+	if (!destroyed) {
+		pr_debug("Deleting handle: %x", syncobj->handle.v);
+		hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+		if (syncobj->handle.v) {
+			hmgrtable_free_handle(&process->handle_table,
+					      HMGRENTRY_TYPE_DXGSYNCOBJECT,
+					      syncobj->handle);
+			syncobj->handle.v = 0;
+			kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
+		}
+		hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+		if (syncobj->monitored_fence)
+			dxgdevice_remove_syncobj(syncobj);
+		else
+			dxgadapter_remove_syncobj(syncobj);
+		if (syncobj->adapter) {
+			kref_put(&syncobj->adapter->adapter_kref,
+				 dxgadapter_release);
+			syncobj->adapter = NULL;
+		}
+	}
+	kref_put(&syncobj->syncobj_kref, dxgsyncobject_release);
+}
+
+void dxgsyncobject_stop(struct dxgsyncobject *syncobj)
+{
+	int stopped = test_and_set_bit(1, &syncobj->flags);
+
+	if (!stopped) {
+		pr_debug("stopping");
+		if (syncobj->monitored_fence) {
+			if (syncobj->mapped_address) {
+				int ret =
+				    dxg_unmap_iospace(syncobj->mapped_address,
+						      PAGE_SIZE);
+
+				(void)ret;
+				pr_debug("unmap fence %d %p\n",
+					ret, syncobj->mapped_address);
+				syncobj->mapped_address = NULL;
+			}
+		}
+	}
+}
+
+void dxgsyncobject_release(struct kref *refcount)
+{
+	struct dxgsyncobject *syncobj;
+
+	syncobj = container_of(refcount, struct dxgsyncobject, syncobj_kref);
+	vfree(syncobj);
+}
drivers/hv/dxgkrnl/dxgkrnl.h +80 -0

134 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgmodule.c +1 -0
index d865ac45f89d..9d339f15a4b7 100644
@@ -158,6 +158,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
 	init_rwsem(&adapter->core_lock);
 
 	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 = dev;
 	guid_to_luid(guid, &adapter->luid);
drivers/hv/dxgkrnl/dxgprocess.c +16 -0
index 1e6500e12a22..30af930cc8c0 100644
@@ -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;
 
@@ -84,6 +85,21 @@ void dxgprocess_destroy(struct dxgprocess *process)
 		}
 	}
 
+	i = 0;
+	while (hmgrtable_next_entry(&process->handle_table, &i, &t, &h, &o)) {
+		switch (t) {
+		case HMGRENTRY_TYPE_DXGSYNCOBJECT:
+			pr_debug("Destroy syncobj: %p %d", o, i);
+			syncobj = o;
+			syncobj->handle.v = 0;
+			dxgsyncobject_destroy(process, syncobj);
+			break;
+		default:
+			pr_err("invalid entry in handle table %d", t);
+			break;
+		}
+	}
+
 	hmgrtable_destroy(&process->handle_table);
 	hmgrtable_destroy(&process->local_handle_table);
 }
drivers/hv/dxgkrnl/dxgvmbus.c +199 -0

217 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +130 -0

148 lines not on this page · raw message

Signature · 1 line
2.35.1
#17 lore raw

PATCH v2 8/24 drivers: hv: dxgkrnl: Operations using GPU sync objects

In reply to Iouri Tarassov

Implement ioctls to submit operations with GPU sync objects:
LX_DXSIGNALSYNCHRONIZATIONOBJECT(D3DKMTSignalSynchronizationObject), LX_DXWAITFORSYNCHRONIZATIONOBJECT(D3DKMTWaitForSynchronizationObject), LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU(D3DKMTSignalSynchronizationObjectFromCpu), LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU(D3DKMTSignalSynchronizationObjectFromGpu), LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2(D3DKMTSignalSynchronizationObjectFromGpu2), LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU(D3DKMTWaitForSynchronizationObjectFromGpu).

GPU synchronization objects are used to synchornize GPU DMA buffer execution between different execution contexts. Operation with sync objects include "signal" and "wait". The wait for a sync object is satisfied when the sync object is signaled.

A signal operation could be submitted to a GPU context or could be signaled by a CPU thread.

The ioctls have common implementation:
- input data is read and validated
- a VM bus message is sent to the host
- the operation status is returned to the caller

To improve performance submitting operations to the host is done asynchronously when the host supports it.

---
 drivers/hv/dxgkrnl/dxgadapter.c |  25 +-
 drivers/hv/dxgkrnl/dxgkrnl.h    |  62 +++
 drivers/hv/dxgkrnl/dxgmodule.c  |  97 +++++
 drivers/hv/dxgkrnl/dxgvmbus.c   | 213 ++++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 693 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/misc.h       |   1 +
 6 files changed, 1088 insertions(+), 3 deletions(-)
drivers/hv/dxgkrnl/dxgadapter.c +22 -3
index 2a9a731c3352..f9aa92d17d52 100644
@@ -893,15 +893,19 @@ struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
 	case _D3DDDI_PERIODIC_MONITORED_FENCE:
 		syncobj->monitored_fence = 1;
 		break;
+	case _D3DDDI_CPU_NOTIFICATION:
+		syncobj->cpu_event = 1;
+		syncobj->host_event = vzalloc(sizeof(struct dxghostevent));
+		if (syncobj->host_event == NULL)
+			goto cleanup;
+		break;
 	default:
 		break;
 	}
 	if (flags.shared) {
 		syncobj->shared = 1;
 		if (!flags.nt_security_sharing) {
-			dev_err(dxgglobaldev,
-				"%s: nt_security_sharing must be set",
-				__func__);
+			pr_err("%s: nt_security_sharing must be set", __func__);
 			goto cleanup;
 		}
 	}
@@ -922,6 +926,8 @@ struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
 	pr_debug("%s 0x%p\n", __func__, syncobj);
 	return syncobj;
 cleanup:
+	if (syncobj->host_event)
+		vfree(syncobj->host_event);
 	if (syncobj)
 		vfree(syncobj);
 	return NULL;
@@ -931,6 +937,7 @@ void dxgsyncobject_destroy(struct dxgprocess *process,
 			   struct dxgsyncobject *syncobj)
 {
 	int destroyed;
+	struct dxghosteventcpu *host_event;
 
 	pr_debug("%s 0x%p", __func__, syncobj);
 
@@ -949,6 +956,16 @@ void dxgsyncobject_destroy(struct dxgprocess *process,
 		}
 		hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
 
+		if (syncobj->cpu_event) {
+			host_event = syncobj->host_event;
+			if (host_event->cpu_event) {
+				eventfd_ctx_put(host_event->cpu_event);
+				if (host_event->hdr.event_id)
+					dxgglobal_remove_host_event(
+						&host_event->hdr);
+				host_event->cpu_event = NULL;
+			}
+		}
 		if (syncobj->monitored_fence)
 			dxgdevice_remove_syncobj(syncobj);
 		else
@@ -988,5 +1005,7 @@ void dxgsyncobject_release(struct kref *refcount)
 	struct dxgsyncobject *syncobj;
 
 	syncobj = container_of(refcount, struct dxgsyncobject, syncobj_kref);
+	if (syncobj->host_event)
+		vfree(syncobj->host_event);
 	vfree(syncobj);
 }
drivers/hv/dxgkrnl/dxgkrnl.h +62 -0

104 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgmodule.c +97 -0

109 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.c +213 -0

231 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +693 -0

732 lines not on this page · raw message

drivers/hv/dxgkrnl/misc.h +1 -0
index 41abdc504bc2..f56d21b48814 100644
@@ -26,6 +26,7 @@ extern const struct d3dkmthandle zerohandle;
  * When a lower lock ois held, the higher lock should not be acquired.
  *
  * device_list_mutex
+ * host_event_list_mutex
  * channel_lock
  * fd_mutex
  * plistmutex
Signature · 1 line
2.35.1
#18 lore raw

PATCH v2 9/24 drivers: hv: dxgkrnl: Sharing of dxgresource objects

In reply to Iouri Tarassov

Implement creation of shared resource and IOCTLs for sharing dxgresource objects between processes in the virtual machine.

A dxgresource object is a collection of dxgallocation objects. The WDDM API allows addition/removal 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 FD (file descriptor) handles. The name "NT handle" is used to be compatible with Windows implementation.

An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The given FD handle could be sent to another process using any Linux API.

To use a shared resource object in WDDM API calls, the object needs to be opened using its FD handle. An resource object is opened by the following
ioctl: LX_DXOPENRESOURCEFROMNTHANDLE.

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 LX_DXOPENRESOURCEFROMNTHANDLE.

---
 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/ioctl.c      | 786 ++++++++++++++++++++++++++++++++
 5 files changed, 1072 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +81 -0
index f9aa92d17d52..1b8f2b63eb6d 100644
@@ -165,6 +165,17 @@ void dxgadapter_remove_process(struct dxgprocess_adapter *process_info)
 	process_info->adapter_process_list_entry.prev = NULL;
 }
 
+void dxgadapter_remove_shared_resource(struct dxgadapter *adapter,
+				       struct dxgsharedresource *object)
+{
+	down_write(&adapter->shared_resource_list_lock);
+	if (object->shared_resource_list_entry.next) {
+		list_del(&object->shared_resource_list_entry);
+		object->shared_resource_list_entry.next = NULL;
+	}
+	up_write(&adapter->shared_resource_list_lock);
+}
+
 void dxgadapter_add_syncobj(struct dxgadapter *adapter,
 			    struct dxgsyncobject *object)
 {
@@ -492,6 +503,69 @@ void dxgdevice_remove_resource(struct dxgdevice *device,
 	}
 }
 
+struct dxgsharedresource *dxgsharedresource_create(struct dxgadapter *adapter)
+{
+	struct dxgsharedresource *resource;
+
+	resource = vzalloc(sizeof(*resource));
+	if (resource) {
+		INIT_LIST_HEAD(&resource->resource_list_head);
+		kref_init(&resource->sresource_kref);
+		mutex_init(&resource->fd_mutex);
+		resource->adapter = adapter;
+	}
+	return resource;
+}
+
+void dxgsharedresource_destroy(struct kref *refcount)
+{
+	struct dxgsharedresource *resource;
+
+	resource = container_of(refcount, struct dxgsharedresource,
+				sresource_kref);
+	if (resource->runtime_private_data)
+		vfree(resource->runtime_private_data);
+	if (resource->resource_private_data)
+		vfree(resource->resource_private_data);
+	if (resource->alloc_private_data_sizes)
+		vfree(resource->alloc_private_data_sizes);
+	if (resource->alloc_private_data)
+		vfree(resource->alloc_private_data);
+	vfree(resource);
+}
+
+void dxgsharedresource_add_resource(struct dxgsharedresource *shared_resource,
+				    struct dxgresource *resource)
+{
+	down_write(&shared_resource->adapter->shared_resource_list_lock);
+	pr_debug("%s: %p %p", __func__, shared_resource, resource);
+	list_add_tail(&resource->shared_resource_list_entry,
+		      &shared_resource->resource_list_head);
+	kref_get(&shared_resource->sresource_kref);
+	kref_get(&resource->resource_kref);
+	resource->shared_owner = shared_resource;
+	up_write(&shared_resource->adapter->shared_resource_list_lock);
+}
+
+void dxgsharedresource_remove_resource(struct dxgsharedresource
+				       *shared_resource,
+				       struct dxgresource *resource)
+{
+	struct dxgadapter *adapter = shared_resource->adapter;
+
+	down_write(&adapter->shared_resource_list_lock);
+	pr_debug("%s: %p %p", __func__, shared_resource, resource);
+	if (resource->shared_resource_list_entry.next) {
+		list_del(&resource->shared_resource_list_entry);
+		resource->shared_resource_list_entry.next = NULL;
+		kref_put(&shared_resource->sresource_kref,
+			 dxgsharedresource_destroy);
+		resource->shared_owner = NULL;
+		kref_put(&resource->resource_kref, dxgresource_release);
+	}
+	up_write(&adapter->shared_resource_list_lock);
+}
+
 struct dxgresource *dxgresource_create(struct dxgdevice *device)
 {
 	struct dxgresource *resource = vzalloc(sizeof(struct dxgresource));
@@ -534,6 +608,7 @@ void dxgresource_destroy(struct dxgresource *resource)
 	struct d3dkmt_destroyallocation2 args = { };
 	int destroyed = test_and_set_bit(0, &resource->flags);
 	struct dxgdevice *device = resource->device;
+	struct dxgsharedresource *shared_resource;
 
 	if (!destroyed) {
 		dxgresource_free_handle(resource);
@@ -549,6 +624,12 @@ void dxgresource_destroy(struct dxgresource *resource)
 			dxgallocation_destroy(alloc);
 		}
 		dxgdevice_remove_resource(device, resource);
+		shared_resource = resource->shared_owner;
+		if (shared_resource) {
+			dxgsharedresource_remove_resource(shared_resource,
+							  resource);
+			resource->shared_owner = NULL;
+		}
 	}
 	kref_put(&resource->resource_kref, dxgresource_release);
 }
drivers/hv/dxgkrnl/dxgkrnl.h +77 -0

113 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgmodule.c +1 -0
index 1815df8e45fe..3af5a7a3ac74 100644
@@ -250,6 +250,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
 	init_rwsem(&adapter->core_lock);
 
 	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 = dev;
drivers/hv/dxgkrnl/dxgvmbus.c +127 -0

139 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +786 -0

841 lines not on this page · raw message

Signature · 1 line
2.35.1
#19 lore raw

PATCH v2 10/24 drivers: hv: dxgkrnl: Sharing of sync objects

In reply to Iouri Tarassov

Implement creation of a shared sync object and IOCTLs for sharing dxgsyncobject objects between processes in the virtual machine.

Sync objects are shared using FD (file descriptor) handles. The name "NT handle" is used to be compatible with Windows implementation.

An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The created FD handle could be sent to another process using any Linux API.

To use a shared sync object in WDDM API calls, the object needs to be opened using its FD handle. A sync object is opened by the following ioctl:
LX_DXOPENSYNCOBJECTFROMNTHANDLE2.

---
 drivers/hv/dxgkrnl/dxgadapter.c |  83 +++++++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  63 +++++++++
 drivers/hv/dxgkrnl/dxgmodule.c  |   1 +
 drivers/hv/dxgkrnl/dxgvmbus.c   |  63 +++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 240 ++++++++++++++++++++++++++++++++
 5 files changed, 450 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +83 -0
index 1b8f2b63eb6d..e32b4bc16ab8 100644
@@ -176,6 +176,26 @@ void dxgadapter_remove_shared_resource(struct dxgadapter *adapter,
 	up_write(&adapter->shared_resource_list_lock);
 }
 
+void dxgadapter_add_shared_syncobj(struct dxgadapter *adapter,
+				   struct dxgsharedsyncobject *object)
+{
+	down_write(&adapter->shared_resource_list_lock);
+	list_add_tail(&object->adapter_shared_syncobj_list_entry,
+		      &adapter->adapter_shared_syncobj_list_head);
+	up_write(&adapter->shared_resource_list_lock);
+}
+
+void dxgadapter_remove_shared_syncobj(struct dxgadapter *adapter,
+				      struct dxgsharedsyncobject *object)
+{
+	down_write(&adapter->shared_resource_list_lock);
+	if (object->adapter_shared_syncobj_list_entry.next) {
+		list_del(&object->adapter_shared_syncobj_list_entry);
+		object->adapter_shared_syncobj_list_entry.next = NULL;
+	}
+	up_write(&adapter->shared_resource_list_lock);
+}
+
 void dxgadapter_add_syncobj(struct dxgadapter *adapter,
 			    struct dxgsyncobject *object)
 {
@@ -952,6 +972,63 @@ void dxgprocess_adapter_remove_device(struct dxgdevice *device)
 	mutex_unlock(&device->adapter_info->device_list_mutex);
 }
 
+struct dxgsharedsyncobject *dxgsharedsyncobj_create(struct dxgadapter *adapter,
+						    struct dxgsyncobject *so)
+{
+	struct dxgsharedsyncobject *syncobj;
+
+	syncobj = vzalloc(sizeof(*syncobj));
+	if (syncobj) {
+		kref_init(&syncobj->ssyncobj_kref);
+		INIT_LIST_HEAD(&syncobj->shared_syncobj_list_head);
+		syncobj->adapter = adapter;
+		syncobj->type = so->type;
+		syncobj->monitored_fence = so->monitored_fence;
+		dxgadapter_add_shared_syncobj(adapter, syncobj);
+		kref_get(&adapter->adapter_kref);
+		init_rwsem(&syncobj->syncobj_list_lock);
+		mutex_init(&syncobj->fd_mutex);
+	}
+	return syncobj;
+}
+
+void dxgsharedsyncobj_release(struct kref *refcount)
+{
+	struct dxgsharedsyncobject *syncobj;
+
+	syncobj = container_of(refcount, struct dxgsharedsyncobject,
+			       ssyncobj_kref);
+	pr_debug("Destroying shared sync object %p", syncobj);
+	if (syncobj->adapter) {
+		dxgadapter_remove_shared_syncobj(syncobj->adapter,
+							syncobj);
+		kref_put(&syncobj->adapter->adapter_kref,
+				dxgadapter_release);
+	}
+	vfree(syncobj);
+}
+
+void dxgsharedsyncobj_add_syncobj(struct dxgsharedsyncobject *shared,
+				  struct dxgsyncobject *syncobj)
+{
+	pr_debug("%s 0x%p 0x%p", __func__, shared, syncobj);
+	kref_get(&shared->ssyncobj_kref);
+	down_write(&shared->syncobj_list_lock);
+	list_add(&syncobj->shared_syncobj_list_entry,
+		 &shared->shared_syncobj_list_head);
+	syncobj->shared_owner = shared;
+	up_write(&shared->syncobj_list_lock);
+}
+
+void dxgsharedsyncobj_remove_syncobj(struct dxgsharedsyncobject *shared,
+				     struct dxgsyncobject *syncobj)
+{
+	pr_debug("%s 0x%p", __func__, shared);
+	down_write(&shared->syncobj_list_lock);
+	list_del(&syncobj->shared_syncobj_list_entry);
+	up_write(&shared->syncobj_list_lock);
+}
+
 struct dxgsyncobject *dxgsyncobject_create(struct dxgprocess *process,
 					   struct dxgdevice *device,
 					   struct dxgadapter *adapter,
@@ -1086,6 +1163,12 @@ void dxgsyncobject_release(struct kref *refcount)
 	struct dxgsyncobject *syncobj;
 
 	syncobj = container_of(refcount, struct dxgsyncobject, syncobj_kref);
+	if (syncobj->shared_owner) {
+		dxgsharedsyncobj_remove_syncobj(syncobj->shared_owner,
+						syncobj);
+		kref_put(&syncobj->shared_owner->ssyncobj_kref,
+			 dxgsharedsyncobj_release);
+	}
 	if (syncobj->host_event)
 		vfree(syncobj->host_event);
 	vfree(syncobj);
drivers/hv/dxgkrnl/dxgkrnl.h +63 -0

111 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgmodule.c +1 -0
index 3af5a7a3ac74..3928512bcc64 100644
@@ -251,6 +251,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t *guid,
 
 	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 = dev;
drivers/hv/dxgkrnl/dxgvmbus.c +63 -0

69 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +240 -0

312 lines not on this page · raw message

Signature · 1 line
2.35.1
#20 lore raw

PATCH v2 11/24 drivers: hv: dxgkrnl: Creation of hardware queue. Sync object operations to hw queue.

In reply to Iouri Tarassov

- Implement ioctls for creation of the hardware queue objects:
LX_DXCREATEHWQUEUE(D3DKMTCreateHardwareQueue), LX_DXDESTROYHWQUEUE(D3DKMTDestroyHardwareQueue)

- Implement ioctls for sync object operations in hardware queues:
LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE(D3DKMTSubmitSignalSyncObjectsToHwQueue), LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE (D3DKMTSubmitWaitForSyncObjectsToHwQueue)

Hardware queues are used when a compute device supports "hardware scheduling". This means that the compute device itself schedules execution of DMA buffers from hardware queues without CPU intervention. This is as oppose to the "packet scheduling" mode where the software GPU scheduler on the host schedules DMA buffer execution.
A hardware queue belongs to a dxgcontext object and has an associated monitored fence object to track execution progress. The monitored fence object has a mapped CPU address to read the fence value by CPU.

- LX_DXCREATEHWQUEUE, LX_DXDESTROYHWQUEUE
These IOCTLs are used to create/destroy hardware queue objects.

- LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE, LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE
These IOCTLs are used to submit a signal or wait operation for monitored fences to a hardware queue. Monitored fences are used to synchronize execution of commands in queues.

---
 drivers/hv/dxgkrnl/dxgadapter.c |  96 ++++++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  33 ++++
 drivers/hv/dxgkrnl/dxgprocess.c |   4 +
 drivers/hv/dxgkrnl/dxgvmbus.c   | 155 +++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 321 ++++++++++++++++++++++++++++++++
 5 files changed, 609 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +96 -0
index e32b4bc16ab8..78530b40839f 100644
@@ -757,6 +757,9 @@ struct dxgcontext *dxgcontext_create(struct dxgdevice *device)
  */
 void dxgcontext_destroy(struct dxgprocess *process, struct dxgcontext *context)
 {
+	struct dxghwqueue *hwqueue;
+	struct dxghwqueue *tmp;
+
 	pr_debug("%s %p\n", __func__, context);
 	context->object_state = DXGOBJECTSTATE_DESTROYED;
 	if (context->device) {
@@ -768,6 +771,10 @@ void dxgcontext_destroy(struct dxgprocess *process, struct 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);
 }
 
@@ -794,6 +801,38 @@ void dxgcontext_release(struct kref *refcount)
 	vfree(context);
 }
 
+int dxgcontext_add_hwqueue(struct dxgcontext *context,
+			   struct dxghwqueue *hwqueue)
+{
+	int ret = 0;
+
+	down_write(&context->hwqueue_list_lock);
+	if (dxgcontext_is_active(context))
+		list_add_tail(&hwqueue->hwqueue_list_entry,
+			      &context->hwqueue_list_head);
+	else
+		ret = -ENODEV;
+	up_write(&context->hwqueue_list_lock);
+	return ret;
+}
+
+void dxgcontext_remove_hwqueue(struct dxgcontext *context,
+			       struct dxghwqueue *hwqueue)
+{
+	if (hwqueue->hwqueue_list_entry.next) {
+		list_del(&hwqueue->hwqueue_list_entry);
+		hwqueue->hwqueue_list_entry.next = NULL;
+	}
+}
+
+void dxgcontext_remove_hwqueue_safe(struct dxgcontext *context,
+				    struct dxghwqueue *hwqueue)
+{
+	down_write(&context->hwqueue_list_lock);
+	dxgcontext_remove_hwqueue(context, hwqueue);
+	up_write(&context->hwqueue_list_lock);
+}
+
 struct dxgallocation *dxgallocation_create(struct dxgprocess *process)
 {
 	struct dxgallocation *alloc = vzalloc(sizeof(struct dxgallocation));
@@ -1173,3 +1212,60 @@ void dxgsyncobject_release(struct kref *refcount)
 		vfree(syncobj->host_event);
 	vfree(syncobj);
 }
+
+struct dxghwqueue *dxghwqueue_create(struct dxgcontext *context)
+{
+	struct dxgprocess *process = context->device->process;
+	struct dxghwqueue *hwqueue = vzalloc(sizeof(*hwqueue));
+
+	if (hwqueue) {
+		kref_init(&hwqueue->hwqueue_kref);
+		hwqueue->context = context;
+		hwqueue->process = process;
+		hwqueue->device_handle = context->device->handle;
+		if (dxgcontext_add_hwqueue(context, hwqueue) < 0) {
+			kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release);
+			hwqueue = NULL;
+		} else {
+			kref_get(&context->context_kref);
+		}
+	}
+	return hwqueue;
+}
+
+void dxghwqueue_destroy(struct dxgprocess *process, struct dxghwqueue *hwqueue)
+{
+	pr_debug("%s %p\n", __func__, hwqueue);
+	hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+	if (hwqueue->handle.v) {
+		hmgrtable_free_handle(&process->handle_table,
+				      HMGRENTRY_TYPE_DXGHWQUEUE,
+				      hwqueue->handle);
+		hwqueue->handle.v = 0;
+	}
+	if (hwqueue->progress_fence_sync_object.v) {
+		hmgrtable_free_handle(&process->handle_table,
+				      HMGRENTRY_TYPE_MONITOREDFENCE,
+				      hwqueue->progress_fence_sync_object);
+		hwqueue->progress_fence_sync_object.v = 0;
+	}
+	hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+
+	if (hwqueue->progress_fence_mapped_address) {
+		dxg_unmap_iospace(hwqueue->progress_fence_mapped_address,
+				  PAGE_SIZE);
+		hwqueue->progress_fence_mapped_address = NULL;
+	}
+	dxgcontext_remove_hwqueue_safe(hwqueue->context, hwqueue);
+
+	kref_put(&hwqueue->context->context_kref, dxgcontext_release);
+	kref_put(&hwqueue->hwqueue_kref, dxghwqueue_release);
+}
+
+void dxghwqueue_release(struct kref *refcount)
+{
+	struct dxghwqueue *hwqueue;
+
+	hwqueue = container_of(refcount, struct dxghwqueue, hwqueue_kref);
+	vfree(hwqueue);
+}
drivers/hv/dxgkrnl/dxgkrnl.h +33 -0
index 662fa27fd1ed..ac699e27b4cb 100644
@@ -36,6 +36,7 @@ struct dxgresource;
 struct dxgsharedresource;
 struct dxgsyncobject;
 struct dxgsharedsyncobject;
+struct dxghwqueue;
 
 #include "misc.h"
 #include "hmgr.h"
@@ -528,8 +529,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);
 
+/*
+ * 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 objects,
  * which are opened for the same underlying shared resource.
@@ -752,6 +777,14 @@ 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);
drivers/hv/dxgkrnl/dxgprocess.c +4 -0
index 30af930cc8c0..32aad8bfa1a5 100644
@@ -278,6 +278,10 @@ struct dxgdevice *dxgprocess_device_by_object_handle(struct dxgprocess *process,
 			device_handle =
 			    ((struct dxgcontext *)obj)->device_handle;
 			break;
+		case HMGRENTRY_TYPE_DXGHWQUEUE:
+			device_handle =
+			    ((struct dxghwqueue *)obj)->device_handle;
+			break;
 		default:
 			pr_err("invalid handle type: %d\n", t);
 			break;
drivers/hv/dxgkrnl/dxgvmbus.c +155 -0

161 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +321 -0

347 lines not on this page · raw message

Signature · 1 line
2.35.1
#21 lore raw

PATCH v2 12/24 drivers: hv: dxgkrnl: Creation of paging queue objects.

In reply to Iouri Tarassov

LX_DXCREATEPAGINGQUEUE (D3DKMTCreatePagingQueue), LX_DXDESTROYPAGINGQUEUE (D3DKMTDestroyPagingQueue)

These IOCTLs are used to create/destroy a paging queue. Paging queues contains 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.

---
 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/ioctl.c      | 184 ++++++++++++++++++++++++++++++++
 5 files changed, 375 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +89 -0
index 78530b40839f..f4e1d402fdbe 100644
@@ -282,6 +282,7 @@ struct dxgdevice *dxgdevice_create(struct dxgadapter *adapter,
 void dxgdevice_stop(struct dxgdevice *device)
 {
 	struct dxgallocation *alloc;
+	struct dxgpagingqueue *pqueue;
 	struct dxgsyncobject *syncobj;
 
 	pr_debug("%s: %p", __func__, device);
@@ -292,6 +293,10 @@ void dxgdevice_stop(struct dxgdevice *device)
 	dxgdevice_release_alloc_list_lock(device);
 
 	hmgrtable_lock(&device->process->handle_table, DXGLOCK_EXCL);
+	list_for_each_entry(pqueue, &device->pqueue_list_head,
+			    pqueue_list_entry) {
+		dxgpagingqueue_stop(pqueue);
+	}
 	list_for_each_entry(syncobj, &device->syncobj_list_head,
 			    syncobj_list_entry) {
 		dxgsyncobject_stop(syncobj);
@@ -379,6 +384,17 @@ void dxgdevice_destroy(struct dxgdevice *device)
 		dxgdevice_release_context_list_lock(device);
 	}
 
+	{
+		struct dxgpagingqueue *tmp;
+		struct dxgpagingqueue *pqueue;
+
+		pr_debug("destroying paging queues\n");
+		list_for_each_entry_safe(pqueue, tmp, &device->pqueue_list_head,
+					 pqueue_list_entry) {
+			dxgpagingqueue_destroy(pqueue);
+		}
+	}
+
 	/* Guest handles need to be released before the host handles */
 	hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
 	if (device->handle_valid) {
@@ -710,6 +726,26 @@ void dxgdevice_release(struct kref *refcount)
 	vfree(device);
 }
 
+void dxgdevice_add_paging_queue(struct dxgdevice *device,
+				struct dxgpagingqueue *entry)
+{
+	dxgdevice_acquire_alloc_list_lock(device);
+	list_add_tail(&entry->pqueue_list_entry, &device->pqueue_list_head);
+	dxgdevice_release_alloc_list_lock(device);
+}
+
+void dxgdevice_remove_paging_queue(struct dxgpagingqueue *pqueue)
+{
+	struct dxgdevice *device = pqueue->device;
+
+	dxgdevice_acquire_alloc_list_lock(device);
+	if (pqueue->pqueue_list_entry.next) {
+		list_del(&pqueue->pqueue_list_entry);
+		pqueue->pqueue_list_entry.next = NULL;
+	}
+	dxgdevice_release_alloc_list_lock(device);
+}
+
 void dxgdevice_add_syncobj(struct dxgdevice *device,
 			   struct dxgsyncobject *syncobj)
 {
@@ -893,6 +929,59 @@ void dxgallocation_destroy(struct dxgallocation *alloc)
 	vfree(alloc);
 }
 
+struct dxgpagingqueue *dxgpagingqueue_create(struct dxgdevice *device)
+{
+	struct dxgpagingqueue *pqueue;
+
+	pqueue = vzalloc(sizeof(*pqueue));
+	if (pqueue) {
+		pqueue->device = device;
+		pqueue->process = device->process;
+		pqueue->device_handle = device->handle;
+		dxgdevice_add_paging_queue(device, pqueue);
+	}
+	return pqueue;
+}
+
+void dxgpagingqueue_stop(struct dxgpagingqueue *pqueue)
+{
+	int ret;
+
+	if (pqueue->mapped_address) {
+		ret = dxg_unmap_iospace(pqueue->mapped_address, PAGE_SIZE);
+		pr_debug("fence is unmapped %d %p",
+			    ret, pqueue->mapped_address);
+		pqueue->mapped_address = NULL;
+	}
+}
+
+void dxgpagingqueue_destroy(struct dxgpagingqueue *pqueue)
+{
+	struct dxgprocess *process = pqueue->process;
+
+	pr_debug("%s %p %x\n", __func__, pqueue, pqueue->handle.v);
+
+	dxgpagingqueue_stop(pqueue);
+
+	hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+	if (pqueue->handle.v) {
+		hmgrtable_free_handle(&process->handle_table,
+				      HMGRENTRY_TYPE_DXGPAGINGQUEUE,
+				      pqueue->handle);
+		pqueue->handle.v = 0;
+	}
+	if (pqueue->syncobj_handle.v) {
+		hmgrtable_free_handle(&process->handle_table,
+				      HMGRENTRY_TYPE_MONITOREDFENCE,
+				      pqueue->syncobj_handle);
+		pqueue->syncobj_handle.v = 0;
+	}
+	hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+	if (pqueue->device)
+		dxgdevice_remove_paging_queue(pqueue);
+	vfree(pqueue);
+}
+
 struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess *process,
 						     struct dxgadapter *adapter)
 {
drivers/hv/dxgkrnl/dxgkrnl.h +24 -0
index ac699e27b4cb..887a23a5bbf8 100644
@@ -85,6 +85,16 @@ int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hdev);
 void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch);
 void dxgvmbuschannel_receive(void *ctx);
 
+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.
@@ -108,6 +118,10 @@ struct dxghosteventcpu {
 	bool			remove_from_list;
 };
 
+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 execution
  * between GPU contextx/hardware queues or for tracking GPU execution progress.
@@ -499,6 +513,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);
@@ -736,6 +753,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,
drivers/hv/dxgkrnl/dxgprocess.c +4 -0
index 32aad8bfa1a5..d4199995d279 100644
@@ -278,6 +278,10 @@ struct dxgdevice *dxgprocess_device_by_object_handle(struct dxgprocess *process,
 			device_handle =
 			    ((struct dxgcontext *)obj)->device_handle;
 			break;
+		case HMGRENTRY_TYPE_DXGPAGINGQUEUE:
+			device_handle =
+			    ((struct dxgpagingqueue *)obj)->device_handle;
+			break;
 		case HMGRENTRY_TYPE_DXGHWQUEUE:
 			device_handle =
 			    ((struct dxghwqueue *)obj)->device_handle;
drivers/hv/dxgkrnl/dxgvmbus.c +74 -0

80 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +184 -0

202 lines not on this page · raw message

Signature · 1 line
2.35.1
#22 lore raw

Re: [PATCH v2 12/24] drivers: hv: dxgkrnl: Creation of paging queue objects.

Quoted 2 lines · Iouri Tarassov

LX_DXCREATEPAGINGQUEUE (D3DKMTCreatePagingQueue), LX_DXDESTROYPAGINGQUEUE (D3DKMTDestroyPagingQueue)

What does this mean?

confused,

greg k-h

#23 lore raw

PATCH v2 13/24 drivers: hv: dxgkrnl: Submit execution commands to the compute device

In reply to Iouri Tarassov

- LX_DXSUBMITCOMMAND(D3DKMTSubmitCommand)
The IOCTL is used to submit a command buffer to the device, working in the software packet scheduling mode.

- LX_DXSUBMITCOMMANDTOHWQUEUE(D3DKMTSubmitCommandToHwQueue) The IOCTL is used to submit a command buffer to the device, working in the hardware scheduling mode.

Both IOCTLs are asynchronous to improve performance as these are high frequency operations.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |   6 ++
 drivers/hv/dxgkrnl/dxgvmbus.c | 111 +++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 129 ++++++++++++++++++++++++++++++++++
 3 files changed, 246 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +6 -0
index 887a23a5bbf8..cb533d5fe797 100644
@@ -770,6 +770,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
@@ -812,6 +815,9 @@ int dxgvmb_send_destroy_hwqueue(struct dxgprocess *process,
 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
drivers/hv/dxgkrnl/dxgvmbus.c +111 -0

120 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +129 -0

147 lines not on this page · raw message

Signature · 1 line
2.35.1
#24 lore raw

PATCH v2 14/24 drivers: hv: dxgkrnl: Implement LX_DXSHAREOBJECTWITHHOST ioctl

In reply to Iouri Tarassov

- Implement the LX_DXSHAREOBJECTWITHHOST (D3DKMTShareObjectWithHost) IOCTL. This IOCTL is used to create an NT handle on the host for the given shared object. The NT handle is returned to the caller. The caller (usually a compositor) could share the NT handle with the host client, which renders the guest window. The host client can open the shared resource using the NT handle. This way the guest and the host have access to the same object (for example, dxgresource or dxgsyncobject).

- Fix incorrect handling of error results from copy_from_user().

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |  2 ++
 drivers/hv/dxgkrnl/dxgvmbus.c | 60 ++++++++++++++++++++++++++++---
 drivers/hv/dxgkrnl/dxgvmbus.h | 14 ++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 68 ++++++++++++++++++++++++++++-------
 4 files changed, 127 insertions(+), 17 deletions(-)
drivers/hv/dxgkrnl/dxgkrnl.h +2 -0
index cb533d5fe797..e1c718e7b8eb 100644
@@ -846,6 +846,8 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
 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);
 
 void signal_host_cpu_event(struct dxghostevent *eventhdr);
 int ntstatus2int(struct ntstatus status);
drivers/hv/dxgkrnl/dxgvmbus.c +55 -5

98 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.h +14 -0
index 5b455618a2a2..b1434742fa80 100644
@@ -63,6 +63,7 @@ enum dxgkvmb_commandtype_global {
 	DXGK_VMBCOMMAND_QUERYETWSESSION		= 1009,
 	DXGK_VMBCOMMAND_SETIOSPACEREGION	= 1010,
 	DXGK_VMBCOMMAND_COMPLETETRANSACTION	= 1011,
+	DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST	= 1021,
 	DXGK_VMBCOMMAND_INVALID_VM_TO_HOST
 };
 
@@ -848,6 +849,19 @@ struct dxgkvmb_command_getdevicestate_return {
 	struct ntstatus			status;
 };
 
+struct dxgkvmb_command_shareobjectwithhost {
+	struct dxgkvmb_command_vm_to_host hdr;
+	struct d3dkmthandle	device_handle;
+	struct d3dkmthandle	object_handle;
+	u64			reserved;
+};
+
+struct dxgkvmb_command_shareobjectwithhost_return {
+	struct ntstatus	status;
+	u32		alignment;
+	u64		vail_nt_handle;
+};
+
 int
 dxgvmb_send_sync_msg(struct dxgvmbuschannel *channel,
 		     void *command, u32 command_size, void *result,
drivers/hv/dxgkrnl/ioctl.c +56 -12

153 lines not on this page · raw message

Signature · 1 line
2.35.1
#25 lore raw

PATCH v2 15/24 drivers: hv: dxgkrnl: IOCTL to get the dxgdevice state LX_DXGETDEVICESTATE

In reply to Iouri Tarassov

LX_DXGETDEVICESTATE(D3DKMTGetDeviceState)
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 followin 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 counter.
- the dxgdevice object has execution_state_counter counter, which is equal to dxgglobal->device_state_counte at the time when LX_DXGETDEVICESTATE was last called.
- if execution_state_counter is different from evice_state_counter, the dxgk_vmbcommand_getdevicestate VM bus message is sent to the host. Otherwise, the cached value is returned.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  | 11 ++++++
 drivers/hv/dxgkrnl/dxgvmbus.c | 66 +++++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 66 +++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +11 -0
index e1c718e7b8eb..892c95a11368 100644
@@ -249,12 +249,18 @@ void dxgsyncobject_destroy(struct dxgprocess *process,
 void dxgsyncobject_stop(struct dxgsyncobject *syncobj);
 void dxgsyncobject_release(struct kref *refcount);
 
+/*
+ * 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 dxgvmbuschannel	channel;
 	struct delayed_work	dwork;
 	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;
@@ -495,6 +501,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;
 };
 
@@ -823,6 +830,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);
drivers/hv/dxgkrnl/dxgvmbus.c +66 -0

90 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +66 -0

78 lines not on this page · raw message

Signature · 1 line
2.35.1
#26 lore raw

PATCH v2 16/24 drivers: hv: dxgkrnl: Mmap(unmap) CPU address to device allocation: LX_DXLOCK2, LX_DXUNLOCK2

In reply to Iouri Tarassov

- LX_DXLOCK2(D3DKMTLock2) maps a CPU virtual address to a compute device allocation. The allocation could be located in system memory or local device memory.
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
2. The host allocates a portion of the guest IO space and maps it to the allocation backing store. The IO space address is returned back to the guest.
3. The guest allocates a CPU virtual address and maps it to the IO space (dxg_map_iospace).
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.

- LX_DXUNLOCK2(D3DKMTUnlock2) unmaps a CPU virtual address from a compute device allocation.

---
 drivers/hv/dxgkrnl/dxgadapter.c |  11 +++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  14 +++
 drivers/hv/dxgkrnl/dxgvmbus.c   | 107 +++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c      | 161 ++++++++++++++++++++++++++++++++
 4 files changed, 293 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +11 -0
index f4e1d402fdbe..e28f5d3e4210 100644
@@ -885,6 +885,15 @@ void dxgallocation_stop(struct dxgallocation *alloc)
 		vfree(alloc->pages);
 		alloc->pages = NULL;
 	}
+	dxgprocess_ht_lock_exclusive_down(alloc->process);
+	if (alloc->cpu_address_mapped) {
+		dxg_unmap_iospace(alloc->cpu_address,
+				  alloc->num_pages << PAGE_SHIFT);
+		alloc->cpu_address_mapped = false;
+		alloc->cpu_address = NULL;
+		alloc->cpu_address_refcount = 0;
+	}
+	dxgprocess_ht_lock_exclusive_up(alloc->process);
 }
 
 void dxgallocation_free_handle(struct dxgallocation *alloc)
@@ -926,6 +935,8 @@ void dxgallocation_destroy(struct dxgallocation *alloc)
 	}
 	if (alloc->priv_drv_data)
 		vfree(alloc->priv_drv_data);
+	if (alloc->cpu_address_mapped)
+		pr_err("Alloc IO space is mapped: %p", alloc);
 	vfree(alloc);
 }
 
drivers/hv/dxgkrnl/dxgkrnl.h +14 -0
index 892c95a11368..fa46abf0350a 100644
@@ -691,6 +691,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;
@@ -698,6 +700,11 @@ struct dxgallocation {
 	struct vmbus_gpadl		gpadl;
 	/* 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
@@ -811,6 +818,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,
drivers/hv/dxgkrnl/dxgvmbus.c +107 -0

113 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +161 -0

179 lines not on this page · raw message

Signature · 1 line
2.35.1
#27 lore raw

PATCH v2 17/24 drivers: hv: dxgkrnl: IOCTLs to handle GPU allocation properties

In reply to Iouri Tarassov

LX_DXCHANGEVIDEOMEMORYRESERVATION,
LX_DXUPDATEALLOCPROPERTY,
LX_DXSETALLOCATIONPRIORITY,
LX_DXGETALLOCATIONPRIORITY,
LX_DXQUERYALLOCATIONRESIDENCY.

Implement various IOCTLs related to GPU allocations. The IOCTLs are logically simple and have the same implementation pattern:
- Read input data
- Build and send a VM bus message to the host
- Return results to the caller

- LX_DXCHANGEVIDEOMEMORYRESERVATION (D3DKMTChangeMemoryReservation)

- LX_DXUPDATEALLOCPROPERTY (D3DKMTUpdateAllocationProperty) Request the host to update verious properties of an allocation.

- LX_DXSETALLOCATIONPRIORITY, LX_DXGETALLOCATIONPRIORITY Set/get allocation priority, which defines how soon the allocation is evicted from GPU accessible memory.

- LX_DXQUERYALLOCATIONRESIDENCY (D3DKMTQueryAllocationResidency) Queries if the allocation is located in the GPU accessible memory.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |  21 +++
 drivers/hv/dxgkrnl/dxgvmbus.c | 300 ++++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 212 ++++++++++++++++++++++++
 3 files changed, 533 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +21 -0
index fa46abf0350a..128c5cd2be3d 100644
@@ -825,6 +825,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,
@@ -844,6 +861,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,
drivers/hv/dxgkrnl/dxgvmbus.c +300 -0

312 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +212 -0

240 lines not on this page · raw message

Signature · 1 line
2.35.1
#28 lore raw

PATCH v2 18/24 drivers: hv: dxgkrnl: Various simple IOCTLs and unused ones LX_DXQUERYVIDEOMEMORYINFO, LX_DXFLUSHHEAPTRANSITIONS, LX_DXINVALIDATECACHE LX_DXGETSHAREDRESOURCEADAPTERLUID

In reply to Iouri Tarassov

Simple IOCTLs have the same implementation pattern:
- read data from input
- send a synchronous VM bus message to the host
- return result to the caller

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |   8 ++
 drivers/hv/dxgkrnl/dxgvmbus.c |  87 ++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 181 ++++++++++++++++++++++++++++++++++
 3 files changed, 276 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +8 -0
index 128c5cd2be3d..2efad824ae72 100644
@@ -856,6 +856,9 @@ 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_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
@@ -865,6 +868,11 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *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,
drivers/hv/dxgkrnl/dxgvmbus.c +87 -0

99 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +181 -0

249 lines not on this page · raw message

Signature · 1 line
2.35.1
#29 lore raw

PATCH v2 19/24 drivers: hv: dxgkrnl: Simple IOCTLs LX_DXESCAPE, LX_DXMARKDEVICEASERROR, LX_DXQUERYSTATISTICS, LX_DXQUERYCLOCKCALIBRATION

In reply to Iouri Tarassov

These IOCTLs are logically simple:
- input data is read
- a message is sent to the host
- the result is returned to the caller

- LX_DXESCAPE (D3DKMTEscape)
This IOCTL is used to send/receive private data between user mode driver and kernel mode driver. This is an extension of the WDDM APIs.

- LX_DXMARKDEVICEASERROR (D3DKMTMarkDeviceAsError)
The IOCTL is used to bring the dxgdevice object to the error state. Subsequent calls to use the device object will fail.

- LX_DXQUERYSTATISTICS (D3DKMTQuerystatistics)
The IOCTL is used to query various statistics from the compute device on the host.

- LX_DXQUERYCLOCKCALIBRATION
The IOCTL queries clock from the compute device.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |  14 +++
 drivers/hv/dxgkrnl/dxgvmbus.c | 167 +++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 193 ++++++++++++++++++++++++++++++++++
 3 files changed, 374 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +14 -0
index 2efad824ae72..8310dd9b7843 100644
@@ -830,6 +830,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);
@@ -856,6 +859,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);
@@ -868,6 +876,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,
@@ -897,6 +908,9 @@ int dxgvmb_send_get_stdalloc_data(struct dxgdevice *device,
 				  void *prive_alloc_data,
 				  u32 *res_priv_data_size,
 				  void *priv_res_data);
+int dxgvmb_send_query_statistics(struct dxgprocess *process,
+				 struct dxgadapter *adapter,
+				 struct d3dkmt_querystatistics *args);
 int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
 			  void *command,
 			  u32 cmd_size);
drivers/hv/dxgkrnl/dxgvmbus.c +167 -0

188 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +193 -0

241 lines not on this page · raw message

Signature · 1 line
2.35.1
#30 lore raw

Re: [PATCH v2 19/24] drivers: hv: dxgkrnl: Simple IOCTLs LX_DXESCAPE, LX_DXMARKDEVICEASERROR, LX_DXQUERYSTATISTICS, LX_DXQUERYCLOCKCALIBRATION

On Fri, Feb 04, 2022 at 06:34:17PM -0800, Iouri Tarassov wrote:

The subject line does not make sense, it is not a sentence.

Quoted 1 line

These IOCTLs are logically simple:

What is "these"?

Quoted 12 lines

- input data is read
- a message is sent to the host
- the result is returned to the caller

- LX_DXESCAPE (D3DKMTEscape)
This IOCTL is used to send/receive private data between user mode driver and kernel mode driver. This is an extension of the WDDM APIs.

- LX_DXMARKDEVICEASERROR (D3DKMTMarkDeviceAsError)
The IOCTL is used to bring the dxgdevice object to the error state. Subsequent calls to use the device object will fail.

Quoted 6 lines

- LX_DXQUERYSTATISTICS (D3DKMTQuerystatistics)
The IOCTL is used to query various statistics from the compute device on the host.

- LX_DXQUERYCLOCKCALIBRATION
The IOCTL queries clock from the compute device.

Why is this not broken up into one-patch-per-ioctl like I asked?

{sigh}

I'm not reviewing this anymore, please rework it.

thanks,

greg k-h

#31 lore raw

Re: [PATCH v2 19/24] drivers: hv: dxgkrnl: Simple IOCTLs LX_DXESCAPE, LX_DXMARKDEVICEASERROR, LX_DXQUERYSTATISTICS, LX_DXQUERYCLOCKCALIBRATION

Quoted 9 lines · Greg KH
Quoted 4 lines · Iouri Tarassov

on the host.

- LX_DXQUERYCLOCKCALIBRATION
The IOCTL queries clock from the compute device.

Why is this not broken up into one-patch-per-ioctl like I asked?

Hi Greg,

There is an article, which asks not to submit too many patches at once:
Submitting patches: the essential guide to getting your code into the kernel — The Linux Kernel documentation <https://www.kernel.org/doc/html/latest/process/submitting-patches.html><https://www.kernel.org/doc/html/latest/process/submitting-patches.html>

NO!!!! No more huge patch bombs to<https://www.kernel.org/doc/html/latest/process/submitting-patches.html>[email protected] <mailto:linux-kernel%40vger.kernel.org>people!
<https://www.kernel.org/doc/html/latest/process/submitting-patches.html>
<https://www.kernel.org/doc/html/latest/process/submitting-patches.html>

<
<https://www.kernel.org/doc/html/latest/process/submitting-patches.html>https://lore.kernel.org/r/[email protected]
<https://lore.kernel.org/r/[email protected]>>

This is confusing as you are requesting more patches. What options do I have?
- should I remove [email protected] until you are happy with the review?
- can I submit a small number of patches for a non fully functional driver and submit the next portion after they are reviewed and accepted?

Thanks
Iouri

#32 lore raw

PATCH v2 20/24 drivers: hv: dxgkrnl: IOCTLs to offer and reclaim allocations

In reply to Iouri Tarassov

LX_DXOFFERALLOCATIONS {D3DKMTOfferAllocations), LX_DXRECLAIMALLOCATIONS2 (D3DKMTReclaimAllocations)

When a user mode driver does not need to access an allocation, it can "offer" it. This means that the allocation is not in use and it local device memory could be reclaimed and given to another allocation. When the allocation is again needed, the UMD can attempt to"reclaim" the allocation. If the allocation is still in the device local memory, the reclaim operation succeeds. If not the called must restore the content of the allocation before it can be used by the device.
The IOCTLs are implemented by sending messages to the host and returning results back to the caller.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |   8 +++
 drivers/hv/dxgkrnl/dxgvmbus.c | 122 ++++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 119 +++++++++++++++++++++++++++++++++
 3 files changed, 249 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +8 -0
index 8310dd9b7843..52d7d74a93e4 100644
@@ -839,6 +839,14 @@ int dxgvmb_send_set_allocation_priority(struct dxgprocess *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,
drivers/hv/dxgkrnl/dxgvmbus.c +122 -0

128 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +119 -0

137 lines not on this page · raw message

Signature · 1 line
2.35.1
#33 lore raw

PATCH v2 21/24 drivers: hv: dxgkrnl: Ioctls to set/get scheduling priority

In reply to Iouri Tarassov

LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY
LX_DXGETCONTEXTSCHEDULINGPRIORITY
LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY
LX_DXSETCONTEXTSCHEDULINGPRIORITY

A GPU context could have an assigned scheduling priority. The host dxgkrnl driver submits work from contexts to GPU, based on the priority of the contexts.
The IOCTLs simply send requests to the host and return the result back to the caller.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |   9 ++
 drivers/hv/dxgkrnl/dxgvmbus.c |  63 +++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 173 ++++++++++++++++++++++++++++++++++
 3 files changed, 245 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +9 -0
index 52d7d74a93e4..eebb9cee39c3 100644
@@ -839,6 +839,15 @@ int dxgvmb_send_set_allocation_priority(struct dxgprocess *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);
drivers/hv/dxgkrnl/dxgvmbus.c +63 -0

69 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +173 -0

191 lines not on this page · raw message

Signature · 1 line
2.35.1
#34 lore raw

PATCH v2 22/24 drivers: hv: dxgkrnl: IOCTLs to manage allocation residency

In reply to Iouri Tarassov

LX_DXMAKERESIDENT (D3DKMTMakeResident)
LX_DXEVICT (D3DKMTEvict)

An allocation is resident when GPU is setup to access it. The current WDDM design does not support on demand GPU page faulting. An allocation must be resident (be in the local device memory or in non-pageable system memory) before GPU is allowed to access it. Applications need to call D3DKMTMAkeResident to make an allocation resident and D3DKMTEvict to evict it from GPU accessible memory. The IOCTLs send the requests to the host and return the result back.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |   4 +
 drivers/hv/dxgkrnl/dxgvmbus.c |  98 +++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 144 ++++++++++++++++++++++++++++++++++
 3 files changed, 246 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +4 -0
index eebb9cee39c3..70cb31654aac 100644
@@ -784,6 +784,10 @@ int dxgvmb_send_create_allocation(struct dxgprocess *pr, struct dxgdevice *dev,
 int dxgvmb_send_destroy_allocation(struct dxgprocess *pr, struct dxgdevice *dev,
 				   struct d3dkmt_destroyallocation2 *args,
 				   struct d3dkmthandle *alloc_handles);
+int dxgvmb_send_make_resident(struct dxgprocess *pr, struct dxgadapter *adapter,
+			      struct d3dddi_makeresident *args);
+int dxgvmb_send_evict(struct dxgprocess *pr, struct dxgadapter *adapter,
+		      struct d3dkmt_evict *args);
 int dxgvmb_send_submit_command(struct dxgprocess *pr,
 			       struct dxgadapter *adapter,
 			       struct d3dkmt_submitcommand *args);
drivers/hv/dxgkrnl/dxgvmbus.c +98 -0

104 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +144 -0

162 lines not on this page · raw message

Signature · 1 line
2.35.1
#35 lore raw

PATCH v2 23/24 drivers: hv: dxgkrnl: IOCTLs to handle GPU virtual addressing (GPU VA)

In reply to Iouri Tarassov

LX_DXRESERVEGPUVIRTUALADDRESS(D3DKMTReserveGpuVertualAddress) LX_DXFREEGPUVIRTUALADDRESS(D3DKMTFreeGpuVertualAddress) LX_DXMAPGPUVIRTUALADDRESS(D3DKMTMapGpuVertualAddress) LX_DXUPDATEGPUVIRTUALADDRESS(D3DKMTUpdateGpuVertualAddress)

WDDM supports accessing GPU memory by using GPU VAs. Each process has a dedicated GPU VA address space.
A GPU VA could be reserved, mapped to a GPU allocation, updated or freed.
The video memory manager on the host updates GPU page tables for the GPU virtual addresses.
The IOCTLs are simply forwarded to the host and return results to the caller.

---
 drivers/hv/dxgkrnl/dxgkrnl.h  |  10 ++
 drivers/hv/dxgkrnl/dxgvmbus.c | 150 ++++++++++++++++++++++
 drivers/hv/dxgkrnl/ioctl.c    | 230 ++++++++++++++++++++++++++++++++++
 3 files changed, 390 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +10 -0
index 70cb31654aac..4a2b4c7611ff 100644
@@ -791,6 +791,16 @@ int dxgvmb_send_evict(struct dxgprocess *pr, struct dxgadapter *adapter,
 int dxgvmb_send_submit_command(struct dxgprocess *pr,
 			       struct dxgadapter *adapter,
 			       struct d3dkmt_submitcommand *args);
+int dxgvmb_send_map_gpu_va(struct dxgprocess *pr, struct d3dkmthandle h,
+			   struct dxgadapter *adapter,
+			   struct d3dddi_mapgpuvirtualaddress *args);
+int dxgvmb_send_reserve_gpu_va(struct dxgprocess *pr,
+			       struct dxgadapter *adapter,
+			       struct d3dddi_reservegpuvirtualaddress *args);
+int dxgvmb_send_free_gpu_va(struct dxgprocess *pr, struct dxgadapter *adapter,
+			    struct d3dkmt_freegpuvirtualaddress *args);
+int dxgvmb_send_update_gpu_va(struct dxgprocess *pr, struct dxgadapter *adapter,
+			      struct d3dkmt_updategpuvirtualaddress *args);
 int dxgvmb_send_create_sync_object(struct dxgprocess *pr,
 				   struct dxgadapter *adapter,
 				   struct d3dkmt_createsynchronizationobject2
drivers/hv/dxgkrnl/dxgvmbus.c +150 -0

156 lines not on this page · raw message

drivers/hv/dxgkrnl/ioctl.c +230 -0

260 lines not on this page · raw message

Signature · 1 line
2.35.1
#36 lore raw

PATCH v2 24/24 drivers: hv: dxgkrnl: Add support to map guest pages by host

In reply to Iouri Tarassov

Dxgkrnl uses GPADLs to implement GPU allocations around existing system memory. 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 be.
To avoid these limitations the host implemented mapping guest pages. Presence of this support is determined by reading PCI config space. When the support is enabled, dxgkrnl does not use GPADLs and instead
- pins memory pages of an existing system memory buffer
- sends PFNs of the pages to the host via a new VM bus message
- the host maps the PFNs to get access to the memory

---
 drivers/hv/dxgkrnl/Makefile    |   2 +-
 drivers/hv/dxgkrnl/dxgkrnl.h   |   2 +
 drivers/hv/dxgkrnl/dxgmodule.c |  30 ++++++-
 drivers/hv/dxgkrnl/dxgvmbus.c  | 145 +++++++++++++++++++++++----------
 drivers/hv/dxgkrnl/dxgvmbus.h  |  12 +++
 drivers/hv/dxgkrnl/ioctl.c     |   7 +-
 drivers/hv/dxgkrnl/misc.c      |   6 ++
 drivers/hv/dxgkrnl/misc.h      |   1 +
 8 files changed, 155 insertions(+), 50 deletions(-)
drivers/hv/dxgkrnl/Makefile +1 -1
index 745c66bebe5d..eedc678c9c2d 100644
@@ -2,4 +2,4 @@
 # Makefile for the Linux video drivers.
 
 obj-$(CONFIG_DXGKRNL)	+= dxgkrnl.o
-dxgkrnl-y		:= dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
+dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
drivers/hv/dxgkrnl/dxgkrnl.h +2 -0
index 4a2b4c7611ff..2f1399ccc668 100644
@@ -301,6 +301,7 @@ struct dxgglobal {
 	bool			pci_registered;
 	bool			global_channel_initialized;
 	bool			async_msg_enabled;
+	bool			map_guest_pages_enabled;
 };
 
 extern struct dxgglobal		*dxgglobal;
@@ -831,6 +832,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,
drivers/hv/dxgkrnl/dxgmodule.c +29 -1
index 3928512bcc64..0447035eb402 100644
@@ -144,7 +144,7 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
 
 void signal_host_cpu_event(struct dxghostevent *eventhdr)
 {
-	struct  dxghosteventcpu *event = (struct  dxghosteventcpu *)eventhdr;
+	struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
 
 	if (event->remove_from_list ||
 		event->destroy_after_signal) {
@@ -430,6 +430,9 @@ const struct file_operations dxgk_fops = {
 /* Luid of the virtual GPU on the host (struct winluid) */
 #define DXGK_VMBUS_VGPU_LUID_OFFSET	(DXGK_VMBUS_VERSION_OFFSET + \
 					sizeof(u32))
+/* The host caps (dxgk_vmbus_hostcaps) */
+#define DXGK_VMBUS_HOSTCAPS_OFFSET	(DXGK_VMBUS_VGPU_LUID_OFFSET + \
+					sizeof(struct winluid))
 /* The guest writes its capavilities to this adderss */
 #define DXGK_VMBUS_GUESTCAPS_OFFSET	(DXGK_VMBUS_VERSION_OFFSET + \
 					sizeof(u32))
@@ -445,6 +448,23 @@ struct dxgk_vmbus_guestcaps {
 	};
 };
 
+/*
+ * The structure defines features, supported by the host.
+ *
+ * map_guest_memory
+ *   Host can map guest memory pages, so the guest can avoid using GPADLs
+ *   to represent existing system memory allocations.
+ */
+struct dxgk_vmbus_hostcaps {
+	union {
+		struct {
+			u32	map_guest_memory	: 1;
+			u32	reserved		: 31;
+		};
+		u32 host_caps;
+	};
+};
+
 /*
  * A helper function to read PCI config space.
  */
@@ -474,6 +494,7 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
 	u32 vmbus_interface_ver = DXGK_VMBUS_INTERFACE_VERSION;
 	struct winluid vgpu_luid = {};
 	struct dxgk_vmbus_guestcaps guest_caps = {.wsl2 = 1};
+	struct dxgk_vmbus_hostcaps host_caps = {};
 
 	mutex_lock(&dxgglobal->device_mutex);
 
@@ -502,6 +523,13 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
 		if (ret)
 			goto cleanup;
 
+		ret = pci_read_config_dword(dev, DXGK_VMBUS_HOSTCAPS_OFFSET,
+					&host_caps.host_caps);
+		if (ret == 0) {
+			if (host_caps.map_guest_memory)
+				dxgglobal->map_guest_pages_enabled = true;
+		}
+
 		if (dxgglobal->vmbus_ver > DXGK_VMBUS_INTERFACE_VERSION)
 			dxgglobal->vmbus_ver = DXGK_VMBUS_INTERFACE_VERSION;
 	}
drivers/hv/dxgkrnl/dxgvmbus.c +103 -42

179 lines not on this page · raw message

drivers/hv/dxgkrnl/dxgvmbus.h +12 -0
index b1434742fa80..48e97f87e329 100644
@@ -139,6 +139,8 @@ enum dxgkvmb_commandtype {
 	DXGK_VMBCOMMAND_GETCONTEXTSCHEDULINGPRIORITY = 61,
 	DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION	= 62,
 	DXGK_VMBCOMMAND_QUERYRESOURCEINFO	= 64,
+	DXGK_VMBCOMMAND_LOGEVENT		= 65,
+	DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES	= 66,
 	DXGK_VMBCOMMAND_INVALID
 };
 
@@ -245,6 +247,16 @@ struct dxgkvmb_command_setexistingsysmemstore {
 	u32				gpadl;
 };
 
+/* Returns ntstatus */
+struct dxgkvmb_command_setexistingsysmempages {
+	struct dxgkvmb_command_vgpu_to_host hdr;
+	struct d3dkmthandle		device;
+	struct d3dkmthandle		allocation;
+	u32				num_pages;
+	u32				alloc_offset_in_pages;
+	/* u64 pfn_array[num_pages] */
+};
+
 struct dxgkvmb_command_createprocess {
 	struct dxgkvmb_command_vm_to_host hdr;
 	void			*process;
drivers/hv/dxgkrnl/ioctl.c +1 -6
index 26bdcdfeba86..333168f8d813 100644
@@ -30,11 +30,6 @@ struct ioctl_desc {
 };
 static struct ioctl_desc ioctls[LX_IO_MAX + 1];
 
-static char *errorstr(int ret)
-{
-	return ret < 0 ? "err" : "";
-}
-
 static int dxgsyncobj_release(struct inode *inode, struct file *file)
 {
 	struct dxgsharedsyncobject *syncobj = file->private_data;
@@ -3557,7 +3552,7 @@ dxgk_wait_sync_object_cpu(struct dxgprocess *process, void *__user inargs)
 	}
 
 	ret = dxgvmb_send_wait_sync_object_cpu(process, adapter,
-					       &args, event_id);
+					       &args, true, event_id);
 	if (ret < 0)
 		goto cleanup;
 
drivers/hv/dxgkrnl/misc.c +6 -0
index cb1e0635bebc..39e52b165b27 100644
@@ -35,3 +35,9 @@ u16 *wcsncpy(u16 *dest, const u16 *src, size_t n)
 	dest[i - 1] = 0;
 	return dest;
 }
+
+char *errorstr(int ret)
+{
+	return ret < 0 ? "err" : "";
+}
+
drivers/hv/dxgkrnl/misc.h +1 -0
index f56d21b48814..721d4f5be235 100644
@@ -43,6 +43,7 @@ extern const struct d3dkmthandle zerohandle;
  */
 
 u16 *wcsncpy(u16 *dest, const u16 *src, size_t n);
+char *errorstr(int ret);
 
 enum dxglockstate {
 	DXGLOCK_SHARED,
Signature · 1 line
2.35.1
#37 lore raw
In reply to Iouri Tarassov
Quoted 54 lines · Iouri Tarassov

This is a follow-up on the changes we sent a few weeks back[1]

[1] https://lore.kernel.org/lkml/[email protected]/

The changes since [1]:

- the driver code is split to more patches for easy reviewing
- static variable dxgglobaldev is removed
- various compiler warnings are fixed
- the patch for DXGSYNCFILE is removed. This patch requires more work and will be submitted separately.

Foreword
-------------------------------------------------------
The patches contain implementation of the Hyper-V vGPU / Compute hardware driver, which powers the Windows Subsystem for Linux (WSL) and will soon power the Windows Subsystem for Android (WSA).

This set of patches is rebuilt from ground up and organized in logical layers to better understand how the driver is built, making it easier for reviewers to understand and follow. The first patch introduces headers and driver initialization. The subsequent patches add additional functionality to the driver.

Per earlier feedback, the driver is now located under the Hyper-V node as it is not a classic Linux GPU (KMS/DRM) driver and really only make sense when running under a Windows host under Hyper-V. Although we refer to this driver as vGPU for shorthand, in reality this is a generic virtualization infrastructure for various class of compute accelerators, the most popular and ubiquitous being the GPU. We support virtualization of non-GPU devices through this infrastructure. These devices are exposed to user-space and used by various API and framework, such as CUDA, OpenCL, OpenVINO, OneAPI, DX12, etc...

One critical piece of feedback, provided by the community in our earlier submission, was the lack of an open source user-space to go along with our kernel compute driver. At the time we only had CUDA and DX12 user-space APIs, both of which being closed source. This is a divisive issue in the community and is heavily debated (https://lwn.net/Articles/821817/).

We took this feedback to heart and we spent the last year working on a way to address this key piece of feedback. Working closely with our partner Intel, we're happy to say that we now have a fully open source user-space for the OpenCL, OpenVINO and OneAPI compute family of APIs on Intel GPU platforms. This is supported by this open source project
(https://github.com/intel/compute-runtime).

To make it easy for our partners to build compute drivers, which are usable in both Windows and WSL environment, we provide a library, that provides a stable interface to our compute device abstraction. This was originally part of the libdxcore closed source API, but have now spawn that off into it's own open source project (https://github.com/microsoft/libdxg).

Quoted 5 lines

Between the Intel compute runtime project and libdxg, we now have a fully open source implementation of our virtualized compute stack inside of WSL. We will continue to support both open source user-space API against our compute abstraction as well as closed source one (CUDA, DX12), leaving it to the API owners and partners to decide what makes the most sense for them.

Does the fully open source user-space implementation actually use the entire user-space API exposed by this driver?

It's not entirely clear but it appears that a good portion of the user-space API for this driver is unused and only has corresponding userspace library defines but not any actual usage(in the open source implementation at least).

It seems like it may be a good idea to audit the ioctls and make sure all of them
actually get used by the open source userspace to ensure that we don't have any exposed uapi's which only have closed source userspace consumers.

Quoted 220 lines

A lot of efforts went into addressing community feedback in this revised set of patches and we hope this is getting closer to what the community would like to see.

We're looking forward additional feedback.

Driver overview
-------------------------------------------------------
dxgkrnl is a driver for Hyper-V virtual compute devices, such as vGPU devices, which are projected to a Linux virtual machine (VM) by a Windows host. dxgkrnl works in context of WDDM (Windows Display Driver Model) for GPU or MCDM (Microsoft Compute Driver Model) for non-GPU devices. WDDM/MCDM consists of the following components:
- Graphics or Compute applications
- A graphics or compute user mode API (for example OpenGL, Vulkan, OpenCL, OpenVINO, OneAPI, CUDA, DX12, ...)
- User Mode Driver (UMD), written by a hardware vendor
- optional libdxg library helping UMD portability across Windows and Linux
- dxgkrnl Linux kernel driver (this driver)
- Kernel mode port driver on the Windows host (dxgkrnl.sys / dxgmms*.sys)
- Kernel Mode miniport driver (KMD) on the Windows host, written by a hardware vendor running on the Windows host and interfacing with the hardware device.

dxgkrnl exposes a subset the WDDM/MCDM D3DKMT interface to user space. See
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmthk/
This interface provides user space with an abstracted view and control of compute devices in a portable way across Windows and WSL. It is used for devices such as GPU or AI/ML processors. This interface is mapped to custom IOCTLs on Linux (see d3dkmthk.h).

A more detailed overview of this architecture is available here:
https://devblogs.microsoft.com/directx/directx-heart-linux/

Compute devices are paravirtualized, meaning that the actual communication with the corresponding device happens on the host. The version of dxgkrnl inside of the Linux kernel coordinates with the version of dxgkrnl running on Windows to provide a consistent and portable abstraction for the device that the various APIs and UMD can rely on across Windows and Linux.

Dxgkrnl creates the /dev/dxg device, which can be used to enumerate devices. UMD or an API runtime open the device and send ioctls to create various device objects (dxgdevice, dxgcontext, dxgallocation, etc., defined in dxgkrnl.h) and to submit work to the device. The WDDM objects are represented in user mode as opaque handles (struct d3dkmthandle). Dxgkrnl creates a dxgprocess object for each process, which opens the /dev/dxg device. This object has a handle table, which is used to translate d3dkmt handles to kernel objects. Handle table definitions are in hmgr.h. There is also a global handle table for objects, which do not belong to a particular process.

Driver initialization
-------------------------------------------------------
When dxgkrnl is loaded, dxgkrnl registers for virtual PCI device arrival notifications and VM bus channel device notifications (see dxgmodule.c). When the first virtual device is started, dxgkrnl creates a misc device (/dev/dxg). A user mode client can open the /dev/dxg device and send IOCTLs to enumerate and control virtual compute devices.

Virtual device initialization
-------------------------------------------------------
A virtual device is represented by a dxgadapter object. It is created when the corresponding device arrives on the virtual PCI bus. The device vendor is PCI_VENDOR_ID_MICROSOFT and the device id is PCI_DEVICE_ID_VIRTUAL_RENDER. The adapter is started when the corresponding VM bus channel and the global VM bus channel are initialized.
Dynamic arrival/removal of devices is supported.

Internal objects
-------------------------------------------------------
Dxgkrnl creates various internal objects in response to IOCTL calls. The corresponsing objects are also created on the host. Each object is placed to a process or global handle table. Object handles (d3dkmthandle) are returned to user mode. The object handles are also used to reference objects on the host. Corresponding objects in the guest and the host have the same handle value to avoid handle translation. The internal objects are:
- dxgadapter
Represents a virtual device object. It is created for every device projected by the host to the VM.
- dxgprocess
The object is created for each Linux process, which opens /dxg/dev. It has the object handle table, which holds pointers to all internal objects, which are created by this process.
- dxgcontext
Represents a device execution thread in the packet scheduling mode (as oppose to the hardware scheduling mode).
- dxghwqueue
Represents a device execution thread in the hardware scheduling mode.
- dxgdevice
A collection of device contexts, allocations, resources, sync objects, etc.
- dxgallocation
Represents a device accessible memory allocation.
- dxgresource
A collection of dxgallocation objects. This object could be shared between devices and processes.
- dxgsharedresource
Represents a dxgresource object, which is sharable between processes.
- dxgsyncobject
Represents a device synchronization object, which is used to synchronize execution of the device execution contexts.
- dxgsharedsyncobject
Represent a device synchronization object, which is sharable between processes.
- dxgpagingqueue
Represents a queue, which is used to manage residency of the device allocation objects.

Communications with the host
-------------------------------------------------------
Dxgkrnl communicates with the host via Hyper-V VM bus channels. There is a global channel and a per device channel. The VM bus messages are defined in dxgvmbus.h and the implementation is in dxgvmbus.c.

Most VM bus messages to the host are synchronous. When the host enables the asynchronous mode, some high frequency VM bus messages are sent asynchronously to improve performance. When async messages are enabled, all VM bus messages are sent only via the global channel to maintain the order of messages on the host.

The host could send asynchronous messages to dxgkrnl via the global VM bus channel. The host messages are handled by dxgvmbuschannel_receive().

PCI config space of the device is used to exchange information between the host and the guest during dxgkrnl initialization. Look at dxg_pci_probe_device().

CPU access to device accessible allocations
-------------------------------------------------------
D3DKMT API allows creation of allocations, which are accessible by the device and the CPU. The global VM bus channels has associated IO space, which is used to implement CPU access to CPU visible allocations. For each such allocation the host allocates a portion of the guest IO space and maps it to the allocation memory (it could be in system memory or in device local memory). A user mode application calls the LX_DXLOCK2 ioctl to get the allocation CPU address. Dxgkrnl uses vm_mmap to allocate a user space VA range and maps it to the allocation IO space using io_remap_pfn_range(). This way Linux user mode virtual addresses point to the host system memory or device local memory.

Sharing objects between processes
-------------------------------------------------------
Some dxgkrnl objects could be shared between processes. This includes resources (dxgresource) and synchronization objects (dxgsyncobject).
The WDDM API provides a way to share objects using so called "NT handles". "NT handle" on Windows is a native Windows process handle (HANDLE). "NT handles" are implemented as file descriptors (FD) on Linux.
The LX_DXSHAREOBJECTS ioctl is used to get an FD for a shared object. Before a shared object can be used, it needs to be "opened" to get the "local" d3dkmthandle handle. The LX_DXOPENRESOURCEFROMNTHANDLE and LX_DXOPENSYNCOBJECTFROMNTHANDLE2 aioctls re used to open a shared object.

Iouri Tarassov (24):
drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
drivers: hv: dxgkrnl: Open device file and dxgprocess creation
drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects
drivers: hv: dxgkrnl: Creation of dxgdevice
drivers: hv: dxgkrnl: Creation of dxgcontext objects
drivers: hv: dxgkrnl: Creation of GPU allocations and resources
drivers: hv: dxgkrnl: Create and destroy GPU sync objects
drivers: hv: dxgkrnl: Operations using GPU sync objects
drivers: hv: dxgkrnl: Sharing of dxgresource objects
drivers: hv: dxgkrnl: Sharing of sync objects
drivers: hv: dxgkrnl: Creation of hardware queue. Sync object
operations to hw queue.
drivers: hv: dxgkrnl: Creation of paging queue objects.
drivers: hv: dxgkrnl: Submit execution commands to the compute device
drivers: hv: dxgkrnl: Implement LX_DXSHAREOBJECTWITHHOST ioctl
drivers: hv: dxgkrnl: IOCTL to get the dxgdevice state
LX_DXGETDEVICESTATE
drivers: hv: dxgkrnl: Mmap(unmap) CPU address to device allocation:
LX_DXLOCK2, LX_DXUNLOCK2
drivers: hv: dxgkrnl: IOCTLs to handle GPU allocation properties
drivers: hv: dxgkrnl: Various simple IOCTLs and unused ones
LX_DXQUERYVIDEOMEMORYINFO, LX_DXFLUSHHEAPTRANSITIONS, LX_DXINVALIDATECACHE LX_DXGETSHAREDRESOURCEADAPTERLUID
drivers: hv: dxgkrnl: Simple IOCTLs LX_DXESCAPE,
LX_DXMARKDEVICEASERROR, LX_DXQUERYSTATISTICS, LX_DXQUERYCLOCKCALIBRATION
drivers: hv: dxgkrnl: IOCTLs to offer and reclaim allocations
drivers: hv: dxgkrnl: Ioctls to set/get scheduling priority
drivers: hv: dxgkrnl: IOCTLs to manage allocation residency
drivers: hv: dxgkrnl: IOCTLs to handle GPU virtual addressing (GPU VA)
drivers: hv: dxgkrnl: Add support to map guest pages by host

 MAINTAINERS                     |    7 +
 drivers/hv/Kconfig              |    2 +
 drivers/hv/Makefile             |    1 +
 drivers/hv/dxgkrnl/Kconfig      |   26 +
 drivers/hv/dxgkrnl/Makefile     |    5 +
 drivers/hv/dxgkrnl/dxgadapter.c | 1371 ++++++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  956 ++++++
 drivers/hv/dxgkrnl/dxgmodule.c  |  942 ++++++
 drivers/hv/dxgkrnl/dxgprocess.c |  334 ++
 drivers/hv/dxgkrnl/dxgvmbus.c   | 3750 +++++++++++++++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  882 +++++
 drivers/hv/dxgkrnl/hmgr.c       |  566 ++++
 drivers/hv/dxgkrnl/hmgr.h       |  112 +
 drivers/hv/dxgkrnl/ioctl.c      | 5450 +++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/misc.c       |   43 +
 drivers/hv/dxgkrnl/misc.h       |   96 +
 include/linux/hyperv.h          |   16 +
 include/uapi/misc/d3dkmthk.h    | 1945 +++++++++++
 18 files changed, 16504 insertions(+)
 create mode 100644 drivers/hv/dxgkrnl/Kconfig
 create mode 100644 drivers/hv/dxgkrnl/Makefile
 create mode 100644 drivers/hv/dxgkrnl/dxgadapter.c
 create mode 100644 drivers/hv/dxgkrnl/dxgkrnl.h
 create mode 100644 drivers/hv/dxgkrnl/dxgmodule.c
 create mode 100644 drivers/hv/dxgkrnl/dxgprocess.c
 create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.c
 create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.h
 create mode 100644 drivers/hv/dxgkrnl/hmgr.c
 create mode 100644 drivers/hv/dxgkrnl/hmgr.h
 create mode 100644 drivers/hv/dxgkrnl/ioctl.c
 create mode 100644 drivers/hv/dxgkrnl/misc.c
 create mode 100644 drivers/hv/dxgkrnl/misc.h
 create mode 100644 include/uapi/misc/d3dkmthk.h

--
2.35.1

#38 lore raw
Quoted 2 lines · James Hilliard

Does the fully open source user-space implementation actually use the entire user-space API exposed by this driver?

I think that is the abolute minimum. But more importantly: I don't think we'd want to expose interface in a virtual GPU driver that aren't also supported by a native one.

#39 lore raw
Quoted 8 lines · Christoph Hellwig
Quoted 2 lines · James Hilliard

Does the fully open source user-space implementation actually use the entire user-space API exposed by this driver?

I think that is the abolute minimum. But more importantly: I don't think we'd want to expose interface in a virtual GPU driver that aren't also supported by a native one.

Yeah, that's one of the obvious huge issues with what is being done here, I mean it seems pretty clear that this is all designed to provide a way to run an effectively
entirely closed source graphics/compute stack with Linux and sidestep the lack of a stable kernel driver API by letting vendors target the windows kernel instead
for their closed source drivers.

I think the closed source and WSL specific user space components are the biggest problem with this whole graphics/compute stack potentially as that is what application developers are being encouraged to target.

I mean it's pretty clear this is being designed in a way to ultimately prevent users from running applications on non-WSL Linux systems, Microsoft isn't even hiding that at all as they even list it as a specific goal of the directx related changes
being pushed to mesa(which are designed to interface with the closed source directx
userspace libraries this kernel driver is designed to support):
https://devblogs.microsoft.com/directx/in-the-works-opencl-and-opengl-mapping-layers-to-directx/

Quoted 2 lines
Quoted 2 lines

Make it easier for developers to port their apps to D3D12. For developers looking to move from older OpenCL and OpenGL API versions to D3D12,

Notice that the mapping/compatibility work they are pushing is essentially entirely
one way, it's designed to make Linux applications work on top of the closed source
WSL directx userspace but does not allow applications targeting directx API's to work
without a WSL system in any way.

It's basically classic EEE(https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish) strategy except that it's targeting non-WSL Linux instead of Linux in general for the
extinguish parts(by using a passthrough driver like this to bypass the kernel):

* Embrace: provide OpenCL and OpenGL API compatibility layers so all existing non-directx graphics/compute software works on WSL.

* Extend: add the WSL-only directx graphics/compute user space to Linux and tie it to
a WSL kernel/host while maintaining backwards compatibility with OpenCL and OpenGL API's for any software that doesn't get ported to directx

* Extinguish: encourage application developers to migrate to new WSL-only directx
graphics/compute API's and away from non-WSL specific OpenGL/OpenCL API's

Quoted 6 lines
Quoted 6 lines

We took this feedback to heart and we spent the last year working on a way to address this key piece of feedback. Working closely with our partner Intel, we're happy to say that we now have a fully open source user-space for the OpenCL, OpenVINO and OneAPI compute family of APIs on Intel GPU platforms. This is supported by this open source project
(https://github.com/intel/compute-runtime).

One would really want to see a mapping layer that translates directx API's to open API's,
such as those exposed by the intel compute runtime instead of the other way around.

Fundamentally I think the changes in this series do nothing to address the main issues
in the original series(https://lore.kernel.org/lkml/[email protected]/) as the DX12 userspace components(which are what microsoft wants apps to target) are
still closed source. Having an open source consumer of this driver isn't going to help much
if the main stack being used is closed source. Especially since this driver is designed to
around the closed source DX12 driver constraints and not the open source user space
constraints:
https://lore.kernel.org/all/[email protected]/

Quoted 3 lines
Quoted 3 lines

d3dkmthk.h defines a binary interface to the compute driver. It cannot be changed, because it must
be binary compatible with the Windows display graphics model.

Since the Windows and Linux compute-runtime drivers are developed together there should be no reason one needs to maintain binary compatibility with the Windows display model as opposed to just ensuring each side of the driver can talk with each
other:
https://github.com/intel/compute-runtime/blob/master/FAQ.md#does-neo-support-microsoft-windows

Quoted 3 lines
Quoted 3 lines

Our closed-source driver for Windows is using the same codebase. At this time, we do not support compilation of the stack for Windows. It is our long-term intention to offer that option.

The binary compatibility requirement with d3dkmthk.h is a constraint imposed by only the closed source stack effectively. So we should be able to tweak the kernel binary interface as needed for the purposes of the open source compute-runtime as the Linux side userspace is already effectively hardware specific, tweaking the host side would simply be a matter of getting an updated driver release with the host tweaks which is already a requirement for the compute-runtime. The binary compatibility seems to only be helpful for those wanting to port closed source drivers with minimal changes.

The directx support could instead be built on top of an open source userspace on the Linux side which would allow for one to choose between either a WSL or non-WSL based graphics/compute stack via a reverse of the mapping layer
(https://www.collabora.com/news-and-blog/news-and-events/introducing-opencl-and-opengl-on-directx.html).
But that approach won't lock users into WSL like this one would so it seems unlikely
to happen.