Driver for Hyper-v virtual compute device
Subsystems (2)
v3 cover Driver for Hyper-v virtual compute device
The driver code in the new patch series is split to more simple patches for easy review. The definitions are added to the header files as they become to be used.
The patches introduces a driver for the Hyper-V virtual compute hardware devices. This driver powers the Windows Subsystem for Linux (WSL) and will soon power the Windows Subsystem for Android (WSA).
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 / dxgmms2.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). The libdxg library translates the D3DKMT interface calls to the driver IOCTLs.
A more detailed overview of this architecture is available here:
https://devblogs.microsoft.com/directx/directx-heart-linux/
Virtual compute devices are paravirtualized, meaning that the actual communication with the corresponding device hardware 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 virtual compute devices (also called adapters). 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 compute 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 compute 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 DMA buffers in 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 virtual computed 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 the Linux dxgkrnl driver 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 virtual address 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 ioctls are used to open a shared object
Iouri Tarassov (30):
drivers: hv: dxgkrnl: Add virtual compute device VM bus
channel guids
drivers: hv: dxgkrnl: Driver initialization and loading
drivers: hv: dxgkrnl: Add VM bus message support, initialize VM bus
channels.
drivers: hv: dxgkrnl: Creation of dxgadapter object
drivers: hv: dxgkrnl: Opening of /dev/dxg device and dxgprocess
creation
drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects
drivers: hv: dxgkrnl: Creation of dxgdevice objects
drivers: hv: dxgkrnl: Creation of dxgcontext objects
drivers: hv: dxgkrnl: Creation of compute device allocations and
resources
drivers: hv: dxgkrnl: Creation of compute device sync objects
drivers: hv: dxgkrnl: Operations using sync objects
drivers: hv: dxgkrnl: Sharing of dxgresource objects
drivers: hv: dxgkrnl: Sharing of sync objects
drivers: hv: dxgkrnl: Creation of hardware queues. 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: Share objects with the host
drivers: hv: dxgkrnl: Query the dxgdevice state
drivers: hv: dxgkrnl: Map(unmap) CPU address to device allocation
drivers: hv: dxgkrnl: Manage device allocation properties
drivers: hv: dxgkrnl: Flush heap transitions
drivers: hv: dxgkrnl: Query video memory information
drivers: hv: dxgkrnl: The escape ioctl
drivers: hv: dxgkrnl: Ioctl to put device to error state
drivers: hv: dxgkrnl: Ioctls to query statistics and clock calibration
drivers: hv: dxgkrnl: Offer and reclaim allocations
drivers: hv: dxgkrnl: Ioctls to manage scheduling priority
drivers: hv: dxgkrnl: Manage residency of allocations
drivers: hv: dxgkrnl: Manage compute device virtual addresses
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 | 1375 ++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 962 ++++++ drivers/hv/dxgkrnl/dxgmodule.c | 942 ++++++ drivers/hv/dxgkrnl/dxgprocess.c | 334 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 3788 ++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 868 +++++ drivers/hv/dxgkrnl/hmgr.c | 566 ++++ drivers/hv/dxgkrnl/hmgr.h | 112 + drivers/hv/dxgkrnl/ioctl.c | 5368 +++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/misc.c | 43 + drivers/hv/dxgkrnl/misc.h | 96 + include/linux/hyperv.h | 16 + include/uapi/misc/d3dkmthk.h | 1679 ++++++++++ 18 files changed, 16190 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
Signature · 1 line
2.35.1
PATCH v3 1/30 drivers: hv: dxgkrnl: Add virtual compute device VM bus channel guids
Add VM bus channel guids, which are used by hyper-v virtual compute device driver.
--- include/linux/hyperv.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
include/linux/hyperv.h +16 -0
@@ -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}
Signature · 1 line
2.35.1
PATCH v3 2/30 drivers: hv: dxgkrnl: Driver initialization and loading
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
- Register for PCI and VM bus driver notifications and handle initialization of VM bus channels.
- Connect the dxgkrnl module to the drivers/hv/ Makefile and Kconfig
- Create a MAINTAINERS entry
A VM bus channel is a communication interface between the hyper-v guest and the host. The are two type of VM bus channels, used in the driver:
- the global channel
- per virtual compute device channel
A PCI device is created for each virtual compute device, projected by the host. The device vendor is PCI_VENDOR_ID_MICROSOFT and device id is PCI_DEVICE_ID_VIRTUAL_RENDER. dxg_pci_probe_device handles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VM bus channels.
VM bus interface version is exchanged by reading/writing the PCI config space of the virtual compute device.
The IO space is used to handle CPU accessible compute device allocations. Hyper-v allocates IO space for the global VM bus channel.
--- MAINTAINERS | 7 + drivers/hv/Kconfig | 2 + drivers/hv/Makefile | 1 + drivers/hv/dxgkrnl/Kconfig | 26 ++ drivers/hv/dxgkrnl/Makefile | 5 + drivers/hv/dxgkrnl/dxgkrnl.h | 119 ++++++++ drivers/hv/dxgkrnl/dxgmodule.c | 531 +++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 23 ++ 8 files changed, 714 insertions(+) create mode 100644 drivers/hv/dxgkrnl/Kconfig create mode 100644 drivers/hv/dxgkrnl/Makefile create mode 100644 drivers/hv/dxgkrnl/dxgkrnl.h create mode 100644 drivers/hv/dxgkrnl/dxgmodule.c create mode 100644 include/uapi/misc/d3dkmthk.h
MAINTAINERS +7 -0
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0 +# Configuration for the hyper-v virtual compute driver (dxgkrnl) +# + +config DXGKRNL + tristate "Microsoft Paravirtualized GPU support" + depends on HYPERV + depends on 64BIT || COMPILE_TEST + help + This driver supports paravirtualized virtual compute devices, exposed + by Microsoft Hyper-V when Linux is running inside of a virtual machine + hosted by Windows. The virtual machines needs to be configured to use + host compute adapters. The driver name is dxgkrnl. + + An example of such virtual machine is a Windows Subsystem for + Linux container. When such container is instantiated, the Windows host + assigns compatible host GPU adapters to the container. The corresponding + virtual GPU devices appear on the PCI bus in the container. These + devices are enumerated and accessed by this driver. + + Communications with the driver are done by using the Microsoft libdxcore + library, which translates the D3DKMT interface + <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
@@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for the hyper-v compute device driver (dxgkrnl). + +obj-$(CONFIG_DXGKRNL) += dxgkrnl.o +dxgkrnl-y := dxgmodule.o
drivers/hv/dxgkrnl/dxgkrnl.h new file +119 -0
119 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgmodule.c new file +531 -0
531 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h new file +23 -0
@@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +/* +* Copyright (c) 2019, Microsoft Corporation. +* +* Author: +* Iouri Tarassov <[email protected]> +* +* Dxgkrnl Graphics Driver +* User mode WDDM interface definitions +* +*/ + +#ifndef _D3DKMTHK_H +#define _D3DKMTHK_H + +/* Matches Windows LUID definition */ +struct winluid { +__u32 a; +__u32 b; +}; + +#endif /* _D3DKMTHK_H */
Signature · 1 line
2.35.1
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 23 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
- Register for PCI and VM bus driver notifications and handle initialization of VM bus channels.
- Connect the dxgkrnl module to the
drivers/hv/MakefileandKconfig- Create a
MAINTAINERSentryA VM bus channel is a communication interface between the hyper-v guest and the host. The are two type of VM bus channels, used in the driver:
- the global channel
- per virtual compute device channelA PCI device is created for each virtual compute device, projected by the host. The device vendor is
PCI_VENDOR_ID_MICROSOFTand device id isPCI_DEVICE_ID_VIRTUAL_RENDER.dxg_pci_probe_devicehandles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VM bus channels.
Quoted 7 lines
VM bus interface version is exchanged by reading/writing the PCI config space of the virtual compute device.
The IO space is used to handle CPU accessible compute device allocations. Hyper-v allocates IO space for the global VM bus channel.
Signed-off-by Iouri Tarassov <[email protected]>
Please work with internal developers to get reviews from them first, before requiring the kernel community to point out basic issues. It will save you a lot of time and stop us from feeling like we are having our time wasted.
Some simple examples below that your coworkers should have caught:
drivers/hv/dxgkrnl/dxgkrnl.h line 4
Quoted 7 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0@@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* +* Copyright (c) 2019, Microsoft Corporation.
It is now 2022 :)
drivers/hv/dxgkrnl/dxgkrnl.h line 94
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+void init_ioctls (void );
That is a horrible global function name you just added to the kernel's namespace for a single driver :(
drivers/hv/dxgkrnl/dxgkrnl.h line 100
Quoted 5 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+long dxgk_unlocked_ioctl (struct file *f,unsigned int p1,unsigned long p2); + +static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ];
Why is the cast needed? Shouldn't you use real types in your structures?
drivers/hv/dxgkrnl/dxgkrnl.h line 117
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+/* +* The interface version is used to ensure that the host and the guest use the +* same VM bus protocol. It needs to be incremented every time the VM bus +* interface changes. DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION is +* incremented each time the earlier versions of the interface are no longer +* compatible with the current version. +*/ +#define DXGK_VMBUS_INTERFACE_VERSION_OLD 27 +#define DXGK_VMBUS_INTERFACE_VERSION 40 +#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16
Where do these numbers come from, the hypervisor specification?
drivers/hv/dxgkrnl/dxgkrnl.h line 26
Quoted 6 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +6
-0+/* +* Pointer to the global device data. By design +* there is a single vGPU device on the VM bus and a single /dev/dxg device +* is created. +*/ +struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
drivers/hv/dxgkrnl/dxgkrnl.h line 27
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+#define DXGKRNL_VERSION 0x2216
What does this mean?
drivers/hv/dxgkrnl/dxgkrnl.h line 32
Quoted 5 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+#define PCI_VENDOR_ID_MICROSOFT 0x1414 +#define PCI_DEVICE_ID_VIRTUAL_RENDER 0x008E + +#undef pr_fmt +#define pr_fmt (fmt) "dxgk: " fmt
Use the dev_*() print functions, you are a driver, and you always have a pointer to a struct device. There's no need to ever call pr_*().
drivers/hv/dxgkrnl/dxgkrnl.h line 36
Quoted 4 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+ +// +// Interface from dxgglobal +//
You mix /* */ and // styles for large comment blocks like this. Pick one and use it consistently.
drivers/hv/dxgkrnl/dxgkrnl.h line 41
Quoted 5 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+ +struct vmbus_channel *dxgglobal_get_vmbus (void ) +{ +return dxgglobal->channel.channel; +}
Again, no globals.
drivers/hv/dxgkrnl/dxgkrnl.h line 54
Quoted 13 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +13
-0+/* +* File operations for the /dev/dxg device +*/ + +static int dxgk_open (struct inode *n,struct file *f) +{ +return 0 ; +} + +static int dxgk_release (struct inode *n,struct file *f) +{ +return 0 ; +}
If you do not need open/release, do not provide them.
drivers/hv/dxgkrnl/dxgkrnl.h line 59
Quoted 5 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+ +static ssize_t dxgk_read (struct file *f,char __user *s,size_t len, +loff_t *o) +{ +pr_debug ("file read\n" );
ftrace is your friend, please remove.
Quoted 20 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +20
-0+return 0 ; +} + +static ssize_t dxgk_write (struct file *f,const char __user *s,size_t len, +loff_t *o) +{ +pr_debug ("file write\n" ); +return len; +} + +const struct file_operations dxgk_fops = { + .owner =THIS_MODULE , + .open = dxgk_open, + .release = dxgk_release, + .write = dxgk_write, + .read = dxgk_read, +}; + +/* +* Interface with the PCI driver
drivers/hv/dxgkrnl/dxgkrnl.h line 89
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+*/ + +/* +* Part of the PCI config space of the vGPU device is used for vGPU +* configuration data. Reading/writing of the PCI config space is forwarded +* to the host. +*/ + +/* vGPU VM bus channel instance ID */ +#define DXGK_VMBUS_CHANNEL_ID_OFFSET 192
No tab? Why not?
drivers/hv/dxgkrnl/dxgkrnl.h line 90
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+/* DXGK_VMBUS_INTERFACE_VERSION (u32) */
What is this?
drivers/hv/dxgkrnl/dxgkrnl.h line 92
Quoted 2 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +2
-0+#define DXGK_VMBUS_VERSION_OFFSET (DXGK_VMBUS_CHANNEL_ID_OFFSET + \ + sizeof(guid_t))
offsetof() is your friend, please use it.
drivers/hv/dxgkrnl/dxgkrnl.h line 93
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+/* Luid of the virtual GPU on the host (struct winluid) */
What is a "luid"?
drivers/hv/dxgkrnl/dxgkrnl.h line 95
Quoted 2 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +2
-0+#define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \ + sizeof(u32))
Again, offsetof() please.
drivers/hv/dxgkrnl/dxgkrnl.h line 96
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+/* The guest writes its capavilities to this adderss */
Odd spelling :(
drivers/hv/dxgkrnl/dxgkrnl.h line 98
Quoted 2 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +2
-0+#define DXGK_VMBUS_GUESTCAPS_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \ + sizeof(u32))
offsetof().
drivers/hv/dxgkrnl/dxgkrnl.h line 106
Quoted 8 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +8
-0+static int dxg_probe_vmbus (struct hv_device *hdev, +const struct hv_vmbus_device_id *dev_id) +{ +int ret =0 ; +struct winluid luid; +struct dxgvgpuchannel *vgpuch; + +mutex_lock (&dxgglobal->device_mutex);
Lock the device's mutex, not the global.
Quoted 19 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +19
-0+ +if (uuid_le_cmp (hdev->dev_type, id_table[0 ].guid) ==0 ) { +/* This is a new virtual GPU channel */ +guid_to_luid (&hdev->channel->offermsg.offer.if_instance, &luid); +pr_debug ("vGPU channel: %pUb" , + &hdev->channel->offermsg.offer.if_instance); + vgpuch =vzalloc (sizeof (struct dxgvgpuchannel )); +if (vgpuch ==NULL ) { + ret = -ENOMEM ; + goto error; + } + vgpuch->adapter_luid = luid; + vgpuch->hdev = hdev; +list_add_tail (&vgpuch->vgpu_ch_list_entry, + &dxgglobal->vgpu_ch_list_head); + }else if (uuid_le_cmp (hdev->dev_type, id_table[1 ].guid) ==0 ) { +/* This is the global Dxgkgnl channel */ +pr_debug ("Global channel: %pUb" , + &hdev->channel->offermsg.offer.if_instance);
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+if (dxgglobal->hdev) { +/* This device should appear only once */ +pr_err ("global channel already present\n" ); + ret = -EBADE ; + goto error; + } + dxgglobal->hdev = hdev; + }else { +/* Unknown device type */ +pr_err ("probe: unknown device type\n" );
dev_err().
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+ ret = -EBADE ;
-ENODEV
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+ goto error;
No need for this goto.
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 8 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +8
-0+ } + +error: + +mutex_unlock (&dxgglobal->device_mutex); + +if (ret) +pr_debug ("err: %s %d" , __func__, ret);
dev_dbg()
Also, pr_debug() and dev_dbg() already provide you with the function name, you never need to add it again.
Quoted 36 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +36
-0+return ret; +} + +static int dxg_remove_vmbus (struct hv_device *hdev) +{ +int ret =0 ; +struct dxgvgpuchannel *vgpu_channel; + +mutex_lock (&dxgglobal->device_mutex); + +if (uuid_le_cmp (hdev->dev_type, id_table[0 ].guid) ==0 ) { +pr_debug ("Remove virtual GPU channel\n" ); +list_for_each_entry (vgpu_channel, + &dxgglobal->vgpu_ch_list_head, + vgpu_ch_list_entry) { +if (vgpu_channel->hdev == hdev) { +list_del (&vgpu_channel->vgpu_ch_list_entry); +vfree (vgpu_channel); +break ; + } + } + }else if (uuid_le_cmp (hdev->dev_type, id_table[1 ].guid) ==0 ) { +pr_debug ("Remove global channel device\n" ); +dxgglobal_destroy_global_channel (); + }else { +/* Unknown device type */ +pr_err ("remove: unknown device type\n" ); + ret = -EBADE ; + } + +mutex_unlock (&dxgglobal->device_mutex); +if (ret) +pr_debug ("err: %s %d" , __func__, ret); +return ret; +} +
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+MODULE_DEVICE_TABLE (vmbus, id_table); + +static struct hv_driver dxg_drv = { + .name =KBUILD_MODNAME , + .id_table = id_table, + .probe = dxg_probe_vmbus, + .remove = dxg_remove_vmbus, + .driver = { + .probe_type =PROBE_PREFER_ASYNCHRONOUS , + },
Odd indentation :(
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 4 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+}; + +/* +* Interface with Linux kernel
What was the code above this???
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 5 lines
+ */
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+ +static int dxgglobal_create (void ) +{ +int ret =0 ;
No need for this variable.
Quoted 25 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +25
-0+ + dxgglobal =vzalloc (sizeof (struct dxgglobal )); +if (!dxgglobal) +return -ENOMEM ; + +INIT_LIST_HEAD (&dxgglobal->plisthead); +mutex_init (&dxgglobal->plistmutex); +mutex_init (&dxgglobal->device_mutex); + +INIT_LIST_HEAD (&dxgglobal->vgpu_ch_list_head); + +init_rwsem (&dxgglobal->channel_lock); + +pr_debug ("dxgglobal_init end\n" ); +return ret; +} + +static void dxgglobal_destroy (void ) +{ +if (dxgglobal) { +if (dxgglobal->vmbus_registered) +vmbus_driver_unregister (&dxg_drv); + +dxgglobal_destroy_global_channel (); +
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+if (dxgglobal->pci_registered) +pci_unregister_driver (&dxg_pci_drv); + +vfree (dxgglobal); + dxgglobal =NULL ; + } +} + +/* +* Driver entry points
???? Entry into what?
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 7 lines
+ */
drivers/hv/dxgkrnl/dxgkrnl.h new file +6
-0+ +static int __init dxg_drv_init (void ) +{ +int ret; + +
Too many blank lines.
Quoted 4 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+ ret =dxgglobal_create (); +if (ret) { +pr_err ("dxgglobal_init failed" ); +return -ENOMEM ;
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+ } + + ret =vmbus_driver_register (&dxg_drv); +if (ret) { +pr_err ("vmbus_driver_register failed: %d" , ret); +return ret; + } + dxgglobal->vmbus_registered = true; + +pr_info ("%s Version: %x" , __func__,DXGKRNL_VERSION );
When drivers work, they are quiet.
Also, in-kernel modules do not have a version, they are part of the kernel tree, and that's the "version" they have. You can drop the individual version here, it makes no sense anymore.
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 4 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+#ifndef _D3DKMTHK_H +#define _D3DKMTHK_H + +/* Matches Windows LUID definition */
That does not describe much :(
drivers/hv/dxgkrnl/dxgkrnl.h
Quoted 3 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +3
-0+struct winluid { +__u32 a; +__u32 b;
No kernel doc documentation? What is "a"? "b"?
I'll stop here in the patch series.
Again, have your coworkers review this first and have them put their names as part of the signed-off-by chain so that we know they agree with the submission.
thanks,
greg k-h
Wei Liu
maintainerRe: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 76 lines · Greg KH
Quoted 23 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
- Register for PCI and VM bus driver notifications and handle initialization of VM bus channels.
- Connect the dxgkrnl module to the
drivers/hv/MakefileandKconfig- Create a
MAINTAINERSentryA VM bus channel is a communication interface between the hyper-v guest and the host. The are two type of VM bus channels, used in the driver:
- the global channel
- per virtual compute device channelA PCI device is created for each virtual compute device, projected by the host. The device vendor is
PCI_VENDOR_ID_MICROSOFTand device id isPCI_DEVICE_ID_VIRTUAL_RENDER.dxg_pci_probe_devicehandles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VM bus channels.Quoted 7 lines
VM bus interface version is exchanged by reading/writing the PCI config space of the virtual compute device.
The IO space is used to handle CPU accessible compute device allocations. Hyper-v allocates IO space for the global VM bus channel.
Signed-off-by Iouri Tarassov <[email protected]>Please work with internal developers to get reviews from them first, before requiring the kernel community to point out basic issues. It will save you a lot of time and stop us from feeling like we are having our time wasted.
Some simple examples below that your coworkers should have caught:
drivers/hv/dxgkrnl/dxgkrnl.h line 4
Quoted 7 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0@@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* +* Copyright (c) 2019, Microsoft Corporation. It is now 2022 :)
drivers/hv/dxgkrnl/dxgkrnl.h line 94
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+void init_ioctls (void );That is a horrible global function name you just added to the kernel's namespace for a single driver :(
drivers/hv/dxgkrnl/dxgkrnl.h line 100
Quoted 5 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+long dxgk_unlocked_ioctl (struct file *f,unsigned int p1,unsigned long p2); + +static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ];Why is the cast needed? Shouldn't you use real types in your structures?
drivers/hv/dxgkrnl/dxgkrnl.h line 117
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+/* +* The interface version is used to ensure that the host and the guest use the +* same VM bus protocol. It needs to be incremented every time the VM bus +* interface changes. DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION is +* incremented each time the earlier versions of the interface are no longer +* compatible with the current version. +*/ +#define DXGK_VMBUS_INTERFACE_VERSION_OLD 27 +#define DXGK_VMBUS_INTERFACE_VERSION 40 +#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16Where do these numbers come from, the hypervisor specification?
Quoted 12 lines
drivers/hv/dxgkrnl/dxgkrnl.h line 26
Quoted 6 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +6
-0+/* +* Pointer to the global device data. By design +* there is a single vGPU device on the VM bus and a single /dev/dxg device +* is created. +*/ +struct dxgglobal *dxgglobal;No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
I definitely think splitting is doable, but I also understand why Iouri does not want to do it _now_ given there is no such a model for multiple devices yet, so anything we put into the per-device structure could be incomplete and it requires further changing when such a model arrives later.
Iouri, please correct me if I have the wrong mental model here.
All in all, I hope this is not going to be a deal breaker for the acceptance of this driver.
Thanks,
Wei.
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 104 lines · Wei Liu
Quoted 76 lines · Greg KH
Quoted 23 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
- Register for PCI and VM bus driver notifications and handle initialization of VM bus channels.
- Connect the dxgkrnl module to the
drivers/hv/MakefileandKconfig- Create a
MAINTAINERSentryA VM bus channel is a communication interface between the hyper-v guest and the host. The are two type of VM bus channels, used in the driver:
- the global channel
- per virtual compute device channelA PCI device is created for each virtual compute device, projected by the host. The device vendor is
PCI_VENDOR_ID_MICROSOFTand device id isPCI_DEVICE_ID_VIRTUAL_RENDER.dxg_pci_probe_devicehandles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VM bus channels.Quoted 7 lines
VM bus interface version is exchanged by reading/writing the PCI config space of the virtual compute device.
The IO space is used to handle CPU accessible compute device allocations. Hyper-v allocates IO space for the global VM bus channel.
Signed-off-by Iouri Tarassov <[email protected]>Please work with internal developers to get reviews from them first, before requiring the kernel community to point out basic issues. It will save you a lot of time and stop us from feeling like we are having our time wasted.
Some simple examples below that your coworkers should have caught:
drivers/hv/dxgkrnl/dxgkrnl.h line 4
Quoted 7 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0@@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* +* Copyright (c) 2019, Microsoft Corporation. It is now 2022 :)
drivers/hv/dxgkrnl/dxgkrnl.h line 94
Quoted 1 line
drivers/hv/dxgkrnl/dxgkrnl.h new file +1
-0+void init_ioctls (void );That is a horrible global function name you just added to the kernel's namespace for a single driver :(
drivers/hv/dxgkrnl/dxgkrnl.h line 100
Quoted 5 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+long dxgk_unlocked_ioctl (struct file *f,unsigned int p1,unsigned long p2); + +static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ];Why is the cast needed? Shouldn't you use real types in your structures?
drivers/hv/dxgkrnl/dxgkrnl.h line 117
Quoted 10 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +10
-0+/* +* The interface version is used to ensure that the host and the guest use the +* same VM bus protocol. It needs to be incremented every time the VM bus +* interface changes. DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION is +* incremented each time the earlier versions of the interface are no longer +* compatible with the current version. +*/ +#define DXGK_VMBUS_INTERFACE_VERSION_OLD 27 +#define DXGK_VMBUS_INTERFACE_VERSION 40 +#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16Where do these numbers come from, the hypervisor specification?
Quoted 12 lines
drivers/hv/dxgkrnl/dxgkrnl.h line 26
Quoted 6 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +6
-0+/* +* Pointer to the global device data. By design +* there is a single vGPU device on the VM bus and a single /dev/dxg device +* is created. +*/ +struct dxgglobal *dxgglobal;No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
I definitely think splitting is doable, but I also understand why Iouri does not want to do it _now_ given there is no such a model for multiple devices yet, so anything we put into the per-device structure could be incomplete and it requires further changing when such a model arrives later.
Quoted 7 lines
Iouri, please correct me if I have the wrong mental model here.
All in all, I hope this is not going to be a deal breaker for the acceptance of this driver.
Thanks,
Wei.
I agree with Wei that there always be global driver data.
The driver reflects what the host offers and also it must provide the same interface to user mode as the host driver does. This is because we want the user mode clients to use the same device interface as if they are working on the host directly.
By design a single global VMBus channel is offered by the host and a single /dev/dxg device is created. The /dev/dxg device provides interface to enumerate virtual compute devices via an ioctl.
If we are to change this model, we would need to make changes to user mode clients, which is a big re-design change, affecting many hardware vendors.
Thanks
Iouri
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 94 lines · Iouri Tarassov
Quoted 93 lines · Wei Liu
Quoted 6 lines · Greg KH
Quoted 5 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
Quoted 1 line
Quoted 1 line
- Register for PCI and VM bus driver notifications and
handle initialization of VM bus channels.
Quoted 1 line
Quoted 1 line
- Connect the dxgkrnl module to the
drivers/hv/Makefileand
KconfigQuoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
- Create a
MAINTAINERSentry
A VM bus channel is a communication interface between thehyper-v guest
Quoted 4 lines
Quoted 4 lines
and the host. The are two type of VM bus channels, used in the driver:
- the global channel
- per virtual compute device channelQuoted 1 line
Quoted 1 line
A PCI device is created for each virtual compute device,
projected
Quoted 7 lines
Quoted 7 lines
by the host. The device vendor is
PCI_VENDOR_ID_MICROSOFTand device id isPCI_DEVICE_ID_VIRTUAL_RENDER.dxg_pci_probe_devicehandles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VM bus channels.Quoted 1 line
Quoted 1 line
VM bus interface version is exchanged by reading/writing the PCI
config
Quoted 19 lines
Quoted 5 lines
space of the virtual compute device.
Quoted 1 line
Quoted 1 line
The IO space is used to handle CPU accessible compute device
allocations. Hyper-v allocates IO space for the global VM bus channel.
Quoted 1 line
Quoted 1 line
Signed-off-by Iouri Tarassov <[email protected]>Please work with internal developers to get reviews from them first,
before requiring the kernel community to point out basic issues. It will save you a lot of time and stop us from feeling like we are having our time wasted.
Quoted 11 lines
Some simple examples below that your coworkers should have caught:
Quoted 1 line
---
/dev/null+++
b/drivers/hv/dxgkrnl/dxgkrnl.hdrivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0@@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* +* Copyright (c) 2019, Microsoft Corporation. It is now 2022 :)
Quoted 1 line
+void
init_ioctls(void);That is a horrible global function name you just added to the
kernel's
Quoted 2 lines
namespace for a single driver :(
Quoted 1 line
Quoted 1 line
+long dxgk_unlocked_ioctl(struct file *f, unsigned int p1,
unsigned long p2);
Quoted 24 lines
Quoted 5 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+ +static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ];Why is the cast needed? Shouldn't you use real types in your
structures?
Quoted 18 lines
Quoted 1 line
+/*
+ * The interface version is used to ensure that the host and the guest use the
+ * same VM bus protocol. It needs to be incremented every time the VM bus
+ * interface changes.DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSIONis
+ * incremented each time the earlier versions of the interface are no longer
+ * compatible with the current version.
+ */drivers/hv/dxgkrnl/dxgkrnl.h new file +3
-0+#define DXGK_VMBUS_INTERFACE_VERSION_OLD 27 +#define DXGK_VMBUS_INTERFACE_VERSION 40 +#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16Where do these numbers come from, the hypervisor specification?
Quoted 1 line
+/*
+ * Pointer to the global device data. By design
+ * there is a single vGPU device on the VM bus and a single/dev/dxgdevice
+ * is created.
+ */
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for yourdriver.
Quoted 4 lines
The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
I definitely think splitting is doable, but I also understand why Iouri does not want to do it _now_ given there is no such a model for multiple devices yet, so anything we put into the per-device structure could be incomplete and it requires further changing when such a model arrives later.
Iouri, please correct me if I have the wrong mental model here.
Quoted 7 lines
Quoted 5 lines
All in all, I hope this is not going to be a deal breaker for the acceptance of this driver.
Thanks,
Wei.I agree with Wei that there always be global driver data.
Why?
Quoted 4 lines
The driver reflects what the host offers and also it must provide the same interface to user mode as the host driver does. This is because we want the user mode clients to use the same device interface as if they are working on the host directly.
That's fine, put that state in the device interface.
Quoted 3 lines
By design a single global VMBus channel is offered by the host and a single
/dev/dxgdevice is created. The/dev/dxgdevice provides interface to enumerate virtual compute devices via an ioctl.
You have device data for each vmbus channel given to the driver, use that.
Quoted 2 lines
If we are to change this model, we would need to make changes to user mode clients, which is a big re-design change, affecting many hardware vendors.
This should not be visible to userspace at all. If so, you are really doing something odd.
thanks,
greg k-h
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
In reply to Wei LiuQuoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
Quoted 10 lines
I definitely think splitting is doable, but I also understand why Iouri does not want to do it _now_ given there is no such a model for multiple devices yet, so anything we put into the per-device structure could be incomplete and it requires further changing when such a model arrives later.
Iouri, please correct me if I have the wrong mental model here.
All in all, I hope this is not going to be a deal breaker for the acceptance of this driver.
For my reviews, yes it will be.
Again, it should be easier to keep things in a per-device state than not as the proper lifetime rules and the like are automatically handled for you. If you have global data, you have to manage that all on your own and it is _MUCH_ harder to review that you got it correct.
Please fix, it will make your life easier as well.
thanks,
greg k-h
Wei Liu
maintainerRe: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 17 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at drivers/iommu/intel/iommu.c. There are a bunch of lists like static LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.
Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */
static LIST_HEAD(dxglist);
/* Rename struct dxgglobal to struct dxgstate */
struct dxgstate {
struct list_head dxglist; /* link for dxglist */
/* ... original fields sans device_mutex */
}
/*
* Provide a bunch of helpers manipulate the list. Called in probe /
* remove etc.
*/
struct dxgstate *find_dxgstate(...);
void remove_dxgstate(...);
int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use dev_set_drvdata to stash the dxgstate into the device object? I think that can be done too.
The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */
struct dxgstate { ... };
static int dxg_probe_vmbus(...) {
/* probe successfully */
struct dxgstate *state = kmalloc(...);
/* Fill in dxgstate with information from backend */
/* hdev->dev is the device object from the core driver framework */
dev_set_drvdata(&hdev->dev, state);
}
static int dxg_remove_vmbus(...) {
/* Normal stuff here ...*/
struct dxgstate *state = dev_get_drvdata(...);
dev_set_drvdata(..., NULL);
kfree(state);
}
/* In all other functions */
void do_things(...) {
struct dxgstate *state = dev_get_drvdata(...);
/* Use state in place of where dxgglobal was needed */
}Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 96 lines · Wei Liu
Quoted 17 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }
Quoted 7 lines
Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.
I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
This will require passing of the global pointer to all functions, which need to access it.
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple /dev/dxgN devices (one per virtual compute device). This would change how the user mode
clients enumerate and communicate with compute devices.
Thanks
Iouri
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 109 lines · Iouri Tarassov
Quoted 96 lines · Wei Liu
Quoted 17 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }Quoted 7 lines
Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
Quoted 8 lines
This will require passing of the global pointer to all functions, which need to access it.
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple
/dev/dxgNdevices (one per virtual compute device).
You have one device per HV device, as the bus already provides you. That's all you really need, right? Who would be opening the same device node multiple times?
Quoted 2 lines
This would change how the user mode
clients enumerate and communicate with compute devices.
What does userspace have to do here? It should just open the device node that is present when needed. How will there be multiple userspace clients for a single HV device?
thanks,
greg k-h
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 122 lines · Greg KH
Quoted 109 lines · Iouri Tarassov
Quoted 96 lines · Wei Liu
Quoted 17 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }Quoted 7 lines
Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
Quoted 8 lines
This will require passing of the global pointer to all functions, which need to access it.
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple
/dev/dxgNdevices (one per virtual compute device).You have one device per HV device, as the bus already provides you. That's all you really need, right? Who would be opening the same device node multiple times?
Quoted 6 lines
Quoted 2 lines
This would change how the user mode
clients enumerate and communicate with compute devices.What does userspace have to do here? It should just open the device node that is present when needed. How will there be multiple userspace clients for a single HV device?
Dxgkrnl creates a single user mode visible device node /dev/dxg. It has nothing to do with a specific hardware compute device on the host. Its purpose is to provide services (IOCTLs) to enumerate and manage virtual compute devices, which represent hardware devices on the host. The VMBus devices are not used directly by user mode clients in the current design.
Virtual compute devices are shared between processes. There could be a Cuda application, Gimp and a Direct3D12 application working at the same time.This is what I mean by saying that there are multiple user mode clients who use the /dev/dxg driver interface. Each of this applications will open the /dev/dxg device node and enumerate/use virtual compute devices.
If we change the way how the virtual compute devices are visible to user mode, the Cuda runtime, Direct3D runtime would need to be changed.
I think we agreed that I will keep the global driver state in the device object as Wei suggested and remove global variables. There still will be a single /dev/dxg device node. Correct?
Thanks
Iouri
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 127 lines · Iouri Tarassov
Quoted 125 lines · Greg KH
Quoted 109 lines · Iouri Tarassov
Quoted 96 lines · Wei Liu
Quoted 17 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }Quoted 7 lines
Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
Quoted 8 lines
This will require passing of the global pointer to all functions, which need to access it.
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple
/dev/dxgNdevices (one per virtual compute device).You have one device per HV device, as the bus already provides you. That's all you really need, right? Who would be opening the same device node multiple times?
Quoted 2 lines
This would change how the user mode
clients enumerate and communicate with compute devices.
Quoted 6 lines
Quoted 3 lines
What does userspace have to do here? It should just open the device node that is present when needed. How will there be multiple userspace clients for a single HV device?
Dxgkrnl creates a single user mode visible device node
/dev/dxg.
When you do that, you have a device to put all of your data on. Use that.
Quoted 5 lines
It has
nothing to do with a specific hardware compute device on the host. Its purpose is to provide services (IOCTLs) to enumerate and manage virtual compute devices, which represent hardware devices on the host. The VMBus devices are not used directly by user mode clients in the current design.
That's horrid, why not just export the virtual compute devices properly through individual device nodes instead?
In essence, you are creating a new syscall here to manage and handle devices for just your driver with the use of this ioctl. That's generally a bad idea.
Quoted 3 lines
Virtual compute devices are shared between processes. There could be a Cuda application, Gimp and a Direct3D12 application working at the same time.
Why are all of those applications sharing anything? How are they sharing anything? If you need to share something across processes, use the existing inter-process ways of sharing stuff that we have today (12+ different apis and counting). Don't create yet-another-one just for your tiny little driver here. That's rude to the rest of the kernel.
Quoted 4 lines
This is what I mean by saying that there are multiple user mode clients who use the
/dev/dxgdriver interface. Each of this applications will open the/dev/dxgdevice node and enumerate/use virtual compute devices.
That seems like an odd model to follow. How many virtual devices do you support? Is there a limit? Why not just enumerate them all to start with? Or if there are too many, why not do it like the raw device and have a single device node that is used to create the virtual devices you wish to use?
Quoted 2 lines
If we change the way how the virtual compute devices are visible to user mode, the Cuda runtime, Direct3D runtime would need to be changed.
We do not care about existing userspace code at this point in time, you are trying to get the kernel api correct here. Once you have done that, then you can go fix up your userspace code to work properly. Anything that came before today is pointless here, right? :)
Quoted 3 lines
I think we agreed that I will keep the global driver state in the device object as Wei suggested and remove global variables. There still will be a single
/dev/dxgdevice node. Correct?
I do not know, as I can't figure out your goals here at all, sorry.
Please go work with some experienced Linux developers in your company. They should be the ones answering these questions for you, not me :)
thanks,
greg k-h
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 169 lines · Greg KH
Quoted 117 lines · Iouri Tarassov
Quoted 116 lines · Greg KH
Quoted 104 lines · Iouri Tarassov
Quoted 92 lines · Wei Liu
Quoted 14 lines · Greg KH
Quoted 6 lines · Wei Liu
Quoted 6 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }Quoted 7 lines
Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
Quoted 8 lines
This will require passing of the global pointer to all functions, which need to access it.
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple
/dev/dxgNdevices (one per virtual compute device).You have one device per HV device, as the bus already provides you. That's all you really need, right? Who would be opening the same device node multiple times?
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
This would change how the user mode
clients enumerate and communicate with compute devices.What does userspace have to do here? It should just open the device node that is present when needed. How will there be multiple userspace clients for a single HV device?
Dxgkrnl creates a single user mode visible device node
/dev/dxg.When you do that, you have a device to put all of your data on. Use that.
Quoted 5 lines
It has
nothing to do with a specific hardware compute device on the host. Its purpose is to provide services (IOCTLs) to enumerate and manage virtual compute devices, which represent hardware devices on the host. The VMBus devices are not used directly by user mode clients in the current design.That's horrid, why not just export the virtual compute devices properly through individual device nodes instead?
In essence, you are creating a new syscall here to manage and handle devices for just your driver with the use of this ioctl. That's generally a bad idea.
Quoted 3 lines
Virtual compute devices are shared between processes. There could be a Cuda application, Gimp and a Direct3D12 application working at the same time.
Why are all of those applications sharing anything? How are they sharing anything? If you need to share something across processes, use the existing inter-process ways of sharing stuff that we have today (12+ different apis and counting). Don't create yet-another-one just for your tiny little driver here. That's rude to the rest of the kernel.
Quoted 4 lines
This is what I mean by saying that there are multiple user mode clients who use the
/dev/dxgdriver interface. Each of this applications will open the/dev/dxgdevice node and enumerate/use virtual compute devices.That seems like an odd model to follow. How many virtual devices do you support? Is there a limit? Why not just enumerate them all to start with? Or if there are too many, why not do it like the raw device and have a single device node that is used to create the virtual devices you wish to use?
Quoted 2 lines
If we change the way how the virtual compute devices are visible to user mode, the Cuda runtime, Direct3D runtime would need to be changed.
We do not care about existing userspace code at this point in time, you are trying to get the kernel api correct here. Once you have done that, then you can go fix up your userspace code to work properly. Anything that came before today is pointless here, right? :)
Quoted 3 lines
I think we agreed that I will keep the global driver state in the device object as Wei suggested and remove global variables. There still will be a single
/dev/dxgdevice node. Correct?
Quoted 8 lines
I do not know, as I can't figure out your goals here at all, sorry.
Please go work with some experienced Linux developers in your company. They should be the ones answering these questions for you, not me :)
thanks,
greg k-h
Thanks Greg and folks for all the feedback. The userspace API provided by this driver is specifically designed to match the Windows compute device abstraction in order to light up a large eco-system of graphics and compute APIs in our various virtualized Linux environment. This is a pretty critical design point as this is the only way we can scale to such a vast eco-system of APIs and their related tools. This enables APIs and framework which are available natively on Linux, such as CUDA, OpenGL, OpenCL, OpenVINO, OneAPI/L0, TensorFlow, Pytorch, soon Vulkan and more in the future and allows them to share the host GPU or compute device when run under our hypervisor. Most of these APIs sit directly on top of our userspace API and changing that abstraction would have major implications. Our D3D/DML userspace components are only implementation details for a subset of those APIs.
We have millions of developers experiencing and enjoying various Linux distributions through our Windows Subsystem for Linux (WSL) and this gives them a way to get hardware acceleration in a large number of important scenarios. WSL makes it trivial for developers to try out Linux totally risk free on over a billion devices, without having to commit to a native install upfront or understand and manually manage VMs. We think this is a pretty valuable proposition to both the Windows and the Linux community and one which has definitely been quite popular.
That being said, we recognize that our virtualization approach makes some folks in the community uncomfortable and the resulting userspace API exposed by our driver will look a bit different than typical Linux driver. Taking into consideration feedback and reception, we decided to pause our upstream effort for this driver. We will keep our driver open source and available in our downstream kernel tree for folks who wants to leverage it in their private kernel.
Thanks, Steve
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 179 lines · Steve Pronovost
Quoted 169 lines · Greg KH
Quoted 117 lines · Iouri Tarassov
Quoted 116 lines · Greg KH
Quoted 104 lines · Iouri Tarassov
Quoted 92 lines · Wei Liu
Quoted 14 lines · Greg KH
Quoted 6 lines · Wei Liu
Quoted 6 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }Quoted 7 lines
Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
Quoted 8 lines
This will require passing of the global pointer to all functions, which need to access it.
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple
/dev/dxgNdevices (one per virtual compute device).You have one device per HV device, as the bus already provides you. That's all you really need, right? Who would be opening the same device node multiple times?
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
This would change how the user mode
clients enumerate and communicate with compute devices.What does userspace have to do here? It should just open the device node that is present when needed. How will there be multiple userspace clients for a single HV device?
Dxgkrnl creates a single user mode visible device node
/dev/dxg.When you do that, you have a device to put all of your data on. Use that.
Quoted 5 lines
It has
nothing to do with a specific hardware compute device on the host. Its purpose is to provide services (IOCTLs) to enumerate and manage virtual compute devices, which represent hardware devices on the host. The VMBus devices are not used directly by user mode clients in the current design.That's horrid, why not just export the virtual compute devices properly through individual device nodes instead?
In essence, you are creating a new syscall here to manage and handle devices for just your driver with the use of this ioctl. That's generally a bad idea.
Quoted 3 lines
Virtual compute devices are shared between processes. There could be a Cuda application, Gimp and a Direct3D12 application working at the same time.
Why are all of those applications sharing anything? How are they sharing anything? If you need to share something across processes, use the existing inter-process ways of sharing stuff that we have today (12+ different apis and counting). Don't create yet-another-one just for your tiny little driver here. That's rude to the rest of the kernel.
Quoted 4 lines
This is what I mean by saying that there are multiple user mode clients who use the
/dev/dxgdriver interface. Each of this applications will open the/dev/dxgdevice node and enumerate/use virtual compute devices.That seems like an odd model to follow. How many virtual devices do you support? Is there a limit? Why not just enumerate them all to start with? Or if there are too many, why not do it like the raw device and have a single device node that is used to create the virtual devices you wish to use?
Quoted 2 lines
If we change the way how the virtual compute devices are visible to user mode, the Cuda runtime, Direct3D runtime would need to be changed.
We do not care about existing userspace code at this point in time, you are trying to get the kernel api correct here. Once you have done that, then you can go fix up your userspace code to work properly. Anything that came before today is pointless here, right? :)
Quoted 3 lines
I think we agreed that I will keep the global driver state in the device object as Wei suggested and remove global variables. There still will be a single
/dev/dxgdevice node. Correct?Quoted 8 lines
I do not know, as I can't figure out your goals here at all, sorry.
Please go work with some experienced Linux developers in your company. They should be the ones answering these questions for you, not me :)
thanks,
greg k-h
Quoted 13 lines
Thanks Greg and folks for all the feedback. The userspace API provided by this driver is specifically designed to match the Windows compute device abstraction in order to light up a large eco-system of graphics and compute APIs in our various virtualized Linux environment. This is a pretty critical design point as this is the only way we can scale to such a vast eco-system of APIs and their related tools. This enables APIs and framework which are available natively on Linux, such as CUDA, OpenGL, OpenCL, OpenVINO, OneAPI/L0, TensorFlow, Pytorch, soon Vulkan and more in the future and allows them to share the host GPU or compute device when run under our hypervisor. Most of these APIs sit directly on top of our userspace API and changing that abstraction would have major implications. Our D3D/DML userspace components are only implementation details for a subset of those APIs.
This feels odd to me as I was only discussing the in-kernel apis, and how this driver does not follow them correctly at all (global device state, odd device creation, etc.) That should have nothing to do with the user/kernel api at all. And surely CUDA and the like never have defined a specific user/kernal api that must be followed, right?
Yes, the existing user/kernel api in this driver is a bit odd, but really, we haven't even started to review that. For you all to just cut-and-run at the first sign of a detailed in-kernel code review is strange, why are you giving up now?
Quoted 9 lines
We have millions of developers experiencing and enjoying various Linux distributions through our Windows Subsystem for Linux (WSL) and this gives them a way to get hardware acceleration in a large number of important scenarios. WSL makes it trivial for developers to try out Linux totally risk free on over a billion devices, without having to commit to a native install upfront or understand and manually manage VMs. We think this is a pretty valuable proposition to both the Windows and the Linux community and one which has definitely been quite popular.
This has nothing to do with how this tiny driver uses the in-kernel apis for creating and managing devices. You are discussing userspace applications here, which is a nice marketing discussion about how many developers you have, but means nothing when it comes to how the kernel code works. So why mention it at all?
Quoted 7 lines
That being said, we recognize that our virtualization approach makes some folks in the community uncomfortable and the resulting userspace API exposed by our driver will look a bit different than typical Linux driver. Taking into consideration feedback and reception, we decided to pause our upstream effort for this driver. We will keep our driver open source and available in our downstream kernel tree for folks who wants to leverage it in their private kernel.
The problems I am pointing out here are how your kernel driver is interacting with the kernel driver model. It has almost nothing to do with the user/kernel api at all.
And even if it did concern the user/kernel api, you already have a userspace library that has to talk to this driver, all you need to do is modify that to handle the expected changes that will happen when you actually get experienced kernel developers to review your code and apis.
I don't understand what you all were expecting here. Did you not want to fit into the kernel tree and take advantage of using the proper functions and interfaces that have been created already? That should enable your users to be able to rely on a more stable and secure and widespread driver for everyone to use.
Instead you are saying that you don't appreciate the time and energy we spent on trying to help you improve your code for your users, and wish to just ignore our help?
By doing this, you are telling all community members that they should not waste their time in reviewing your company's code submissions as they are not appreciated or wanted unless they are just a rubber-stamp approval. That's going to ensure that no one ever reviews your contributions again in the future, which is an odd request, don't you think?
Oh well, it's easy to add a filter to just ignore any future code submissions from your email domain. I'll recommend that all other kernel developers and maintainers do the same as we all have changes to review from companies and developers that actually want our feedback.
best of luck!
greg k-h
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 249 lines · Greg KH
Quoted 176 lines · Steve Pronovost
Quoted 167 lines · Greg KH
Quoted 116 lines · Iouri Tarassov
Quoted 115 lines · Greg KH
Quoted 103 lines · Iouri Tarassov
Quoted 92 lines · Wei Liu
Quoted 14 lines · Greg KH
Quoted 6 lines · Wei Liu
Quoted 6 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }Quoted 7 lines
Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
Quoted 8 lines
This will require passing of the global pointer to all functions, which need to access it.
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple
/dev/dxgNdevices (one per virtual compute device).You have one device per HV device, as the bus already provides you. That's all you really need, right? Who would be opening the same device node multiple times?
Quoted 6 lines
Quoted 5 lines
Quoted 2 lines
This would change how the user mode
clients enumerate and communicate with compute devices.What does userspace have to do here? It should just open the device node that is present when needed. How will there be multiple userspace clients for a single HV device?
Dxgkrnl creates a single user mode visible device node
/dev/dxg.When you do that, you have a device to put all of your data on. Use that.
Quoted 5 lines
It has
nothing to do with a specific hardware compute device on the host. Its purpose is to provide services (IOCTLs) to enumerate and manage virtual compute devices, which represent hardware devices on the host. The VMBus devices are not used directly by user mode clients in the current design.That's horrid, why not just export the virtual compute devices properly through individual device nodes instead?
In essence, you are creating a new syscall here to manage and handle devices for just your driver with the use of this ioctl. That's generally a bad idea.
Quoted 3 lines
Virtual compute devices are shared between processes. There could be a Cuda application, Gimp and a Direct3D12 application working at the same time.
Why are all of those applications sharing anything? How are they sharing anything? If you need to share something across processes, use the existing inter-process ways of sharing stuff that we have today (12+ different apis and counting). Don't create yet-another-one just for your tiny little driver here. That's rude to the rest of the kernel.
Quoted 4 lines
This is what I mean by saying that there are multiple user mode clients who use the
/dev/dxgdriver interface. Each of this applications will open the/dev/dxgdevice node and enumerate/use virtual compute devices.That seems like an odd model to follow. How many virtual devices do you support? Is there a limit? Why not just enumerate them all to start with? Or if there are too many, why not do it like the raw device and have a single device node that is used to create the virtual devices you wish to use?
Quoted 2 lines
If we change the way how the virtual compute devices are visible to user mode, the Cuda runtime, Direct3D runtime would need to be changed.
We do not care about existing userspace code at this point in time, you are trying to get the kernel api correct here. Once you have done that, then you can go fix up your userspace code to work properly. Anything that came before today is pointless here, right? :)
Quoted 3 lines
I think we agreed that I will keep the global driver state in the device object as Wei suggested and remove global variables. There still will be a single
/dev/dxgdevice node. Correct?Quoted 8 lines
I do not know, as I can't figure out your goals here at all, sorry.
Please go work with some experienced Linux developers in your company. They should be the ones answering these questions for you, not me :)
thanks,
greg k-h
Quoted 13 lines
Thanks Greg and folks for all the feedback. The userspace API provided by this driver is specifically designed to match the Windows compute device abstraction in order to light up a large eco-system of graphics and compute APIs in our various virtualized Linux environment. This is a pretty critical design point as this is the only way we can scale to such a vast eco-system of APIs and their related tools. This enables APIs and framework which are available natively on Linux, such as CUDA, OpenGL, OpenCL, OpenVINO, OneAPI/L0, TensorFlow, Pytorch, soon Vulkan and more in the future and allows them to share the host GPU or compute device when run under our hypervisor. Most of these APIs sit directly on top of our userspace API and changing that abstraction would have major implications. Our D3D/DML userspace components are only implementation details for a subset of those APIs.
This feels odd to me as I was only discussing the in-kernel apis, and how this driver does not follow them correctly at all (global device state, odd device creation, etc.) That should have nothing to do with the user/kernel api at all. And surely CUDA and the like never have defined a specific user/kernal api that must be followed, right?
Yes, the existing user/kernel api in this driver is a bit odd, but really, we haven't even started to review that. For you all to just cut-and-run at the first sign of a detailed in-kernel code review is strange, why are you giving up now?
Quoted 9 lines
We have millions of developers experiencing and enjoying various Linux distributions through our Windows Subsystem for Linux (WSL) and this gives them a way to get hardware acceleration in a large number of important scenarios. WSL makes it trivial for developers to try out Linux totally risk free on over a billion devices, without having to commit to a native install upfront or understand and manually manage VMs. We think this is a pretty valuable proposition to both the Windows and the Linux community and one which has definitely been quite popular.
This has nothing to do with how this tiny driver uses the in-kernel apis for creating and managing devices. You are discussing userspace applications here, which is a nice marketing discussion about how many developers you have, but means nothing when it comes to how the kernel code works. So why mention it at all?
Quoted 7 lines
That being said, we recognize that our virtualization approach makes some folks in the community uncomfortable and the resulting userspace API exposed by our driver will look a bit different than typical Linux driver. Taking into consideration feedback and reception, we decided to pause our upstream effort for this driver. We will keep our driver open source and available in our downstream kernel tree for folks who wants to leverage it in their private kernel.
The problems I am pointing out here are how your kernel driver is interacting with the kernel driver model. It has almost nothing to do with the user/kernel api at all.
And even if it did concern the user/kernel api, you already have a userspace library that has to talk to this driver, all you need to do is modify that to handle the expected changes that will happen when you actually get experienced kernel developers to review your code and apis.
I don't understand what you all were expecting here. Did you not want to fit into the kernel tree and take advantage of using the proper functions and interfaces that have been created already? That should enable your users to be able to rely on a more stable and secure and widespread driver for everyone to use.
Instead you are saying that you don't appreciate the time and energy we spent on trying to help you improve your code for your users, and wish to just ignore our help?
By doing this, you are telling all community members that they should not waste their time in reviewing your company's code submissions as they are not appreciated or wanted unless they are just a rubber-stamp approval. That's going to ensure that no one ever reviews your contributions again in the future, which is an odd request, don't you think?
Quoted 8 lines
Oh well, it's easy to add a filter to just ignore any future code submissions from your email domain. I'll recommend that all other kernel developers and maintainers do the same as we all have changes to review from companies and developers that actually want our feedback.
best of luck!
greg k-h
Hey Greg,
Apologies, I didn’t mean to imply we don’t appreciate the feedback from you or the community nor were we looking for a rubber stamp approval. You’ve provided great feedback and we’ll continue to evolve our driver toward this and we will continue to review internally with more experienced Linux kernel developers to get our driver into a better shape that can be upstreamed
It’s clear our code isn’t ready to be included upstream and we don’t want to waste reviewer’s time on it. We take all of the feedback seriously. Last year in our rfc, when we got the feedback that we really needed an open source userspace, we went to great length to get one. We will continue to integrate all of the feedback we have gotten so far.
I totally agree that some of the feedback has nothing to do with the userspace API and we’ll evolve the driver toward that direction, it’s just goodness and will help make our driver simpler and more reliable. We will go back and figure out how to address this feedback, but it will take some time to do it right. The pause below wasn’t meant to imply we’re giving up forever, but that it will take a while before we can attempt again with a patch set that is hopefully better aligned and more mature in the future.
My email below was meant to be a thank you for the feedback, we’ll pause iteration on the current patch set since we have a lot of internalizing to do and some things that will take quite a while to address and we didn’t want to just go silent. but obviously I did a very poor job of communicating that. Let me assure you there is no ill feeling on our end and we do appreciate the feedback, it may take some time but we will be back again :-).
Thanks,
Steve
Wei Liu
maintainerRe: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
In reply to Iouri TarassovQuoted 100 lines · Iouri Tarassov
Quoted 99 lines · Wei Liu
Quoted 17 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Quoted 7 lines
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
It is perhaps easier to draw parallel from an existing driver. I feel like we're talking past each other.
Let's look at
drivers/iommu/intel/iommu.c. There are a bunch of lists likestatic LIST_HEAD(dmar_rmrr_units). During the probing phase, new units will be added to the list. I this the current code is following this model. dxgglobal fulfills the role of a list.Setting aside the question of whether it makes sense to keep a copy of the per-VM state in each device instance, I can see the code be changed to:
struct mutex device_mutex; /* split out from dxgglobal */ static LIST_HEAD(dxglist); /* Rename struct dxgglobal to struct dxgstate */ struct dxgstate { struct list_head dxglist; /* link for dxglist */ /* ... original fields sans device_mutex */ } /* * Provide a bunch of helpers manipulate the list. Called in probe / * remove etc. */ struct dxgstate *find_dxgstate(...); void remove_dxgstate(...); int add_dxgstate(...);This model is well understood and used in tree. It is just that it doesn't provide much value in doing this now since the list will only contain one element. I hope that you're not saying we cannot even use a per-module pointer to quickly get the data structure we want to use, right?
Are you suggesting Iouri use
dev_set_drvdatato stash the dxgstate into the device object? I think that can be done too.The code can be changed as:
/* Rename struct dxgglobal to dxgstate and remove unneeded fields */ struct dxgstate { ... }; static int dxg_probe_vmbus(...) { /* probe successfully */ struct dxgstate *state = kmalloc(...); /* Fill in dxgstate with information from backend */ /* hdev->dev is the device object from the core driver framework */ dev_set_drvdata(&hdev->dev, state); } static int dxg_remove_vmbus(...) { /* Normal stuff here ...*/ struct dxgstate *state = dev_get_drvdata(...); dev_set_drvdata(..., NULL); kfree(state); } /* In all other functions */ void do_things(...) { struct dxgstate *state = dev_get_drvdata(...); /* Use state in place of where dxgglobal was needed */ }Iouri, notice this doesn't change anything regarding how userspace is designed. This is about how kernel organises its data.
Quoted 9 lines
Quoted 4 lines
I hope what I wrote above can bring our understanding closer.
Thanks,
Wei.I can certainly remove dxgglobal and keep the pointer to the global state in the device object.
No, no more global pointer needed. You just call dev_drv_setdata in the place that you assign to the global pointer.
Quoted 3 lines
This will require passing of the global pointer to all functions, which need to access it.
And in the place you need the global pointer, call dev_drv_getdata.
Quoted 7 lines
Maybe my understanding of the Greg's suggestion was not correct. I thought the suggestion was
to have multiple
/dev/dxgNdevices (one per virtual compute device). This would change how the user mode
No. You still have only one /dev/dxg here.
Wei.
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
In reply to Greg KHQuoted 35 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
Quoted 10 lines
I definitely think splitting is doable, but I also understand why Iouri does not want to do it _now_ given there is no such a model for multiple devices yet, so anything we put into the per-device structure could be incomplete and it requires further changing when such a model arrives later.
Iouri, please correct me if I have the wrong mental model here.
All in all, I hope this is not going to be a deal breaker for the acceptance of this driver.
Quoted 6 lines
For my reviews, yes it will be.
Again, it should be easier to keep things in a per-device state than not as the proper lifetime rules and the like are automatically handled for you. If you have global data, you have to manage that all on your own and it is _MUCH_ harder to review that you got it correct.
Hi Greg,
I do not really see how the driver be written without the global data. Let's review the design.
Dxgkrnl acts as the aggregator of all virtual compute devices, projected by the host. It needs to do operations, which do not belong to a particular compute device. For example, cross device synchronization and resource sharing.
A PCI device device is created for each virtual compute device. Therefore, there should be a global list of objects and a mutex to synchronize access to the list.
A VMBus channel is offered by the host for each compute device. The list of the VMBus channels should be global.
A global VMBus channel is offered by the host. The channel does not belong to any particular compute device, so it must be global.
IO space is shared by all compute devices, so its parameters should be global.
Dxgkrnl needs to maintain a list of processes, which opened compute device objects. Dxgkrnl maintains private state for each process and when a process opens the /dev/dxg device, Dxgkrnl needs to find if the process state is already created by walking the global process list.
Now, where to keep this global state? It could be kept in the /dev/dxg private device structure. But this structure is not available when, for example, dxg_pci_probe_device() or dxg_probe_vmbus() is called.
Can there be multiple /dev/dxg devices? No. Because the /dev/dxg device represents the driver itself, not a particular compute device.
I am not sure what design model you have in mind when saying there should be no global data. Could you please explain keeping in mind the above requirements?
Thanks
Iouri
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 39 lines · Iouri Tarassov
Quoted 37 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
Quoted 10 lines
I definitely think splitting is doable, but I also understand why Iouri does not want to do it _now_ given there is no such a model for multiple devices yet, so anything we put into the per-device structure could be incomplete and it requires further changing when such a model arrives later.
Iouri, please correct me if I have the wrong mental model here.
All in all, I hope this is not going to be a deal breaker for the acceptance of this driver.
For my reviews, yes it will be.
Quoted 8 lines
Quoted 4 lines
Again, it should be easier to keep things in a per-device state than not as the proper lifetime rules and the like are automatically handled for you. If you have global data, you have to manage that all on your own and it is _MUCH_ harder to review that you got it correct.
Hi Greg,
I do not really see how the driver be written without the global data. Let's review the design.
I see it the other way around. It's easier to make it without a static structure, it is more work to keep it as you have done so here. Do it correctly to start with and you will not have any of these issues going forward.
Quoted 1 line
Dxgkrnl acts as the aggregator of all virtual compute devices, projected by the host. It needs to do operations, which do not belong to a particular compute device. For example, cross device synchronization and resource sharing.
Then hang your data off of your device node structure that you created. Why ignore that?
Quoted 1 line
A PCI device device is created for each virtual compute device. Therefore, there should be a global list of objects and a mutex to synchronize access to the list.
Woah, what? You create a fake PCI device for each virtual device? If so, great, then you are now a PCI bus and create the PCI devices properly so that the PCI core can handle and manage them and then assign them to your driver. You should NEVER have a global list of these devices, as that is what the driver model should be managing. Not you!
Quoted 1 line
A VMBus channel is offered by the host for each compute device. The list of the VMBus channels should be global.
The vmbus channels are already handled by the driver core. Use those devices that are given to you. You don't need to manage them at all.
Quoted 1 line
A global VMBus channel is offered by the host. The channel does not belong to any particular compute device, so it must be global.
That channel is attached to your driver, use the device given to your driver by the bus. It's not "global" in any sense of the word.
And what's up with your lack of line wrapping?
Quoted 1 line
IO space is shared by all compute devices, so its parameters should be global.
Huh? If that's the case then you have bigger problems. Use the aux bus for devices that share io space. That is what it was created for, do not ignore the functionality that Linux already provides you by trying to go around it and writing your own code. Use the frameworks we have already debugged and support. This is why your Linux driver should be at least 1/3 smaller than drivers for other operating systems.
Quoted 1 line
Dxgkrnl needs to maintain a list of processes, which opened compute device objects. Dxgkrnl maintains private state for each process and when a process opens the
/dev/dxgdevice, Dxgkrnl needs to find if the process state is already created by walking the global process list.
That "list" is handled by the device node structure that was opened. It's not "global" at all. Again, just like any other device node in Linux, this isn't a new thing or anything special at all.
Quoted 1 line
Now, where to keep this global state? It could be kept in the
/dev/dxgprivate device structure. But this structure is not available when, for example,dxg_pci_probe_device()ordxg_probe_vmbus()is called.
Then your design is wrong. It's as simple as that. Fix it.
Quoted 1 line
Can there be multiple
/dev/dxgdevices? No. Because the/dev/dxgdevice represents the driver itself, not a particular compute device.
Then fix this. Make your compute devices store the needed information when they are created. Again, we have loads of examples in the kernel, this is nothing new.
Quoted 1 line
I am not sure what design model you have in mind when saying there should be no global data. Could you please explain keeping in mind the above requirements?
Please see all of my responses above, and please use more \n characters in the future :)
good luck!
greg k-h
Wei Liu
maintainerRe: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 45 lines · Greg KH
Quoted 44 lines · Iouri Tarassov
Quoted 41 lines · Greg KH
Quoted 8 lines · Wei Liu
Quoted 7 lines
Quoted 1 line
+struct dxgglobal *dxgglobal;
No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
Quoted 7 lines
This may not be as big an issue as you thought. The device discovery is still done via the normal VMBus probing routine. For all intents and purposes the dxgglobal structure can be broken down into per device fields and a global structure which contains the protocol versioning information -- my understanding is there will always be a global structure to hold information related to the backend, regardless of how many devices there are.
Then that is wrong and needs to be fixed. Drivers should almost never have any global data, that is not how Linux drivers work. What happens when you get a second device in your system for this? Major rework would have to happen and the code will break. Handle that all now as it takes less work to make this per-device than it does to have a global variable.
Quoted 10 lines
I definitely think splitting is doable, but I also understand why Iouri does not want to do it _now_ given there is no such a model for multiple devices yet, so anything we put into the per-device structure could be incomplete and it requires further changing when such a model arrives later.
Iouri, please correct me if I have the wrong mental model here.
All in all, I hope this is not going to be a deal breaker for the acceptance of this driver.
For my reviews, yes it will be.
Again, it should be easier to keep things in a per-device state than not as the proper lifetime rules and the like are automatically handled for you. If you have global data, you have to manage that all on your own and it is _MUCH_ harder to review that you got it correct.
Quoted 11 lines
Quoted 3 lines
Hi Greg,
I do not really see how the driver be written without the global data. Let's review the design.
I see it the other way around. It's easier to make it without a static structure, it is more work to keep it as you have done so here. Do it correctly to start with and you will not have any of these issues going forward.
Quoted 1 line
Dxgkrnl acts as the aggregator of all virtual compute devices, projected by the host. It needs to do operations, which do not belong to a particular compute device. For example, cross device synchronization and resource sharing.
Hey Iouri, please fix your text wrapping.
Greg, I have to admit I only started paying close attention to this series a few days ago, so I don't claim I know a lot.
Quoted 8 lines
Then hang your data off of your device node structure that you created. Why ignore that?
Quoted 3 lines
A PCI device device is created for each virtual compute device. Therefore, there should be a global list of objects and a mutex to synchronize access to the list.
Quoted 7 lines
Woah, what? You create a fake PCI device for each virtual device? If so, great, then you are now a PCI bus and create the PCI devices properly so that the PCI core can handle and manage them and then assign them to your driver. You should NEVER have a global list of these devices, as that is what the driver model should be managing. Not you!
No, there is no fake PCI device. The device object is still coming from the PCI core driver. There is code to match against PCI vendor ID and device ID, and follow the usual way of managing PCI device.
Iouri understands device specific state should be encapsulated in the private data field in their respective device. And I believe the code can perhaps be rewritten to better conform to Linux kernel's model.
That should address the issue ...
Quoted 6 lines
Quoted 2 lines
A VMBus channel is offered by the host for each compute device. The list of the VMBus channels should be global.
The vmbus channels are already handled by the driver core. Use those devices that are given to you. You don't need to manage them at all.
here ...
Quoted 6 lines
Quoted 2 lines
A global VMBus channel is offered by the host. The channel does not belong to any particular compute device, so it must be global.
That channel is attached to your driver, use the device given to your driver by the bus. It's not "global" in any sense of the word.
here ...
Quoted 5 lines
And what's up with your lack of line wrapping?
Quoted 2 lines
IO space is shared by all compute devices, so its parameters should be global.
Quoted 8 lines
Huh? If that's the case then you have bigger problems. Use the aux bus for devices that share io space. That is what it was created for, do not ignore the functionality that Linux already provides you by trying to go around it and writing your own code. Use the frameworks we have already debugged and support. This is why your Linux driver should be at least 1/3 smaller than drivers for other operating systems.
To be fair, auxiliary bus was only added in 5.11, while this series was written long before that. Unfortunately one only has so much time to follow Linux kernel development closely. I admit this is the first time I hear about it. :-)
Quoted 10 lines
Quoted 5 lines
Dxgkrnl needs to maintain a list of processes, which opened compute device objects. Dxgkrnl maintains private state for each process and when a process opens the
/dev/dxgdevice, Dxgkrnl needs to find if the process state is already created by walking the global process list.That "list" is handled by the device node structure that was opened. It's not "global" at all. Again, just like any other device node in Linux, this isn't a new thing or anything special at all.
Again, the state can be associated with the private_data field in struct file.
Quoted 7 lines
Quoted 4 lines
Now, where to keep this global state? It could be kept in the
/dev/dxgprivate device structure. But this structure is not available when, for example,dxg_pci_probe_device()ordxg_probe_vmbus()is called.Then your design is wrong. It's as simple as that. Fix it.
Quoted 8 lines
Quoted 3 lines
Can there be multiple
/dev/dxgdevices? No. Because the/dev/dxgdevice represents the driver itself, not a particular compute device.Then fix this. Make your compute devices store the needed information when they are created. Again, we have loads of examples in the kernel, this is nothing new.
At this point, I think Iouri and I have settled on more encapsulation is needed. Yet there is something I don't know how to square yet. That is, devices (either from vmbus or pci) don't form a clear hierarchy. If there isn't a linked list or some sort to organize them it would be difficult to cross-reference. This then goes back to what I wrote earlier in <20220302115334.wemdkznokszlzcpe@liuwe-devbox-debian-v2>. I hope you won't be against using that pattern -- it is used in a lot of places in tree.
Thanks,
Wei.
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 12 lines · Wei Liu
Quoted 11 lines
Quoted 3 lines
A PCI device device is created for each virtual compute device. Therefore, there should be a global list of objects and a mutex to synchronize access to the list.
Woah, what? You create a fake PCI device for each virtual device? If so, great, then you are now a PCI bus and create the PCI devices properly so that the PCI core can handle and manage them and then assign them to your driver. You should NEVER have a global list of these devices, as that is what the driver model should be managing. Not you!
Quoted 3 lines
No, there is no fake PCI device. The device object is still coming from the PCI core driver. There is code to match against PCI vendor ID and device ID, and follow the usual way of managing PCI device.
So it is a real PCI device? Why the confusion?
Quoted 3 lines
Iouri understands device specific state should be encapsulated in the private data field in their respective device. And I believe the code can perhaps be rewritten to better conform to Linux kernel's model.
It has to follow the Linux kernel model, to think otherwise is quite odd.
Quoted 12 lines
Quoted 11 lines
Quoted 2 lines
IO space is shared by all compute devices, so its parameters should be global.
Huh? If that's the case then you have bigger problems. Use the aux bus for devices that share io space. That is what it was created for, do not ignore the functionality that Linux already provides you by trying to go around it and writing your own code. Use the frameworks we have already debugged and support. This is why your Linux driver should be at least 1/3 smaller than drivers for other operating systems.
Quoted 4 lines
To be fair, auxiliary bus was only added in 5.11, while this series was written long before that. Unfortunately one only has so much time to follow Linux kernel development closely. I admit this is the first time I hear about it. :-)
5.11 was over a year ago. We do not take "old" drivers into the kernel tree, and if this series has not been touched for over a year, um, you all have bigger problems here and are just wasting our time :(
Quoted 8 lines
Quoted 4 lines
Then fix this. Make your compute devices store the needed information when they are created. Again, we have loads of examples in the kernel, this is nothing new.
At this point, I think Iouri and I have settled on more encapsulation is needed. Yet there is something I don't know how to square yet. That is, devices (either from vmbus or pci) don't form a clear hierarchy.
That is because devices don't care where they are in the larger kernel tree of devices, they are independant. To try to claim there is a needed hierarchy is quite odd and will cause lots of problems when that heirachy changes by the underlying system.
Quoted 3 lines
If
there isn't a linked list or some sort to organize them it would be difficult to cross-reference.
You should never be touching another device from another one. There are a few rare exceptions but they are rare and you should not use them at all. And if you do have to do so, you better get the reference counting logic correct.
good luck!
greg k-h
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
In reply to Greg KHQuoted 11 lines · Greg KH
drivers/hv/dxgkrnl/dxgmodule.c line 33
Quoted 6 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
drivers/hv/dxgkrnl/dxgmodule.c new file +3
-0+ +#undef pr_fmt +#define pr_fmt (fmt) "dxgk: " fmtUse the dev_*() print functions, you are a driver, and you always have a pointer to a struct device. There's no need to ever call pr_*().
There is no struct device during module initialization until the /dev/dxg device is created. Is it ok to use pr_* functions in this case? Should dev_*(NULL,...) be used? I see other drivers use the pr_* functions in this case (mips.c as an example).
Thanks
Iouri
Quoted 3 lines
thanks,
greg k-h
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 14 lines · Iouri Tarassov
Quoted 11 lines · Greg KH
drivers/hv/dxgkrnl/dxgmodule.c line 33
Quoted 6 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
drivers/hv/dxgkrnl/dxgmodule.c new file +3
-0+ +#undef pr_fmt +#define pr_fmt (fmt) "dxgk: " fmtUse the dev_*() print functions, you are a driver, and you always have a pointer to a struct device. There's no need to ever call pr_*().
Quoted 2 lines
There is no struct device during module initialization until the
/dev/dxgdevice is created.
Then you should not have anything to print out.
Quoted 1 line
Is it ok to use pr_* functions in this case?
Nope.
Quoted 1 line
Should dev_*(NULL,...) be used?
No, not at all, never!
Quoted 2 lines
I see other drivers use the pr_* functions in this case (
mips.cas an example).
There are lots of bad examples in the kernel tree, let's make your code a good one.
thanks,
greg k-h
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
In reply to Greg KHHi Greg,
Thanks a lot for reviewing the patches.
I appreciate the very detailed comments. I my reply I omitted the comments, which I agree with and will address in subsequent patches.
Quoted 9 lines · Greg KH
drivers/hv/dxgkrnl/dxgkrnl.h line 100
Quoted 6 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+long dxgk_unlocked_ioctl (struct file *f,unsigned int p1,unsigned long p2); + +static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ];Why is the cast needed? Shouldn't you use real types in your structures?
The VMBus channel ID, which is GUID, is present in the PCI config space of the compute device. The convention is that the lower part of the GUID is LUID (local unique identifier). This function just converts GUID to LUID. I am not sure what is the ask here.
Quoted 4 lines
Quoted 4 lines
+/*
+ * The interface version is used to ensure that the host and the guest use the
+ * same VM bus protocol. It needs to be incremented every time the VM bus
+ * interface changes.DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSIONis
Quoted 8 lines
drivers/hv/dxgkrnl/dxgkrnl.h line 117
Quoted 6 lines
+ * incremented each time the earlier versions of the interface are no longer
+ * compatible with the current version.
+ */drivers/hv/dxgkrnl/dxgkrnl.h new file +3
-0+#define DXGK_VMBUS_INTERFACE_VERSION_OLD 27 +#define DXGK_VMBUS_INTERFACE_VERSION 40 +#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16Where do these numbers come from, the hypervisor specification?
The definitions are for the VMBus interface between the virtual compute device in the guest and the Windows host. The interface version is updated when the VMBus protocol is changed. These are specific to the virtual compute device, not to the hypervisor.
Quoted 11 lines
drivers/hv/dxgkrnl/dxgmodule.c line 26
Quoted 6 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +6
-0+/* +* Pointer to the global device data. By design +* there is a single vGPU device on the VM bus and a single /dev/dxg device +* is created. +*/ +struct dxgglobal *dxgglobal;No, make this per-device, NEVER have a single device for your driver. The Linux driver model makes it harder to do it this way than to do it correctly. Do it correctly please and have no global structures like this.
This will be addressed in the next version of patches.
Quoted 3 lines
Quoted 1 line
+#define
DXGKRNL_VERSION0x2216What does this mean?
This is the driver implementation version. There are many Microsoft shipped Linux kernels, which include the driver. The version allows to quickly determine, which level of functionality or bug fixes is implemented in the current driver.
Quoted 11 lines
Quoted 10 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +10
-0+ +/* +* Interface with the PCI driver +*/ + +/* +* Part of the PCI config space of the vGPU device is used for vGPU +* configuration data. Reading/writing of the PCI config space is forwarded +* to the host. +*/
Quoted 3 lines
Quoted 1 line
+/*
DXGK_VMBUS_INTERFACE_VERSION(u32) */What is this?
This comment explains that the value of DXGK_VMBUS_INTERFACE_VERSION is located at the offset DXGK_VMBUS_CHANNEL_ID_OFFSET in the PCI config space.
Quoted 4 lines
drivers/hv/dxgkrnl/dxgmodule.c line 115
Quoted 2 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +2
-0+#define DXGK_VMBUS_VERSION_OFFSET (DXGK_VMBUS_CHANNEL_ID_OFFSET + \ + sizeof(guid_t))
offsetof()is your friend, please use it.
There is no structure definition for the PCI config space of the device. Therefore, offsets are computed by using data size.
Quoted 3 lines
Quoted 1 line
+/* Luid of the virtual GPU on the host (struct winluid) */
What is a "luid"?
LUID is "Locally Unique Identifier". It is used in Windows and its value is guaranteed to be unique until the computer reboots. This is similar to GUID, but is it not globally unique. Dxgkrnl on the host uses LUIDs to identify compute adapter objects.
I added a comment to the definition in the header.
Quoted 11 lines
drivers/hv/dxgkrnl/dxgmodule.c line 508
Quoted 8 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +8
-0+ ret =vmbus_driver_register (&dxg_drv); +if (ret) { +pr_err ("vmbus_driver_register failed: %d" , ret); +return ret; + } + dxgglobal->vmbus_registered = true; + +pr_info ("%s Version: %x" , __func__,DXGKRNL_VERSION );When drivers work, they are quiet.
Quoted 3 lines
Also, in-kernel modules do not have a version, they are part of the kernel tree, and that's the "version" they have. You can drop the individual version here, it makes no sense anymore.
Microsoft develops many Linux kernels when the dxgkrnl driver is included (EFLOW, Android, WSL). The kernels are built at different times and might include a different version of the driver. Printing the version allows to quickly determine what functionality and bug fixes are included in the driver.
I see that other in-tree drivers print some information during init_module (like nfblock.c).
This is done for convenience. So instead of tracking multiple kernel versions, we can track the dxgkrnl driver version. I am ok to remove it if it really hurts something. It is only a single line per driver load.
Thanks
Iouri
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 20 lines · Iouri Tarassov
Hi Greg,
Thanks a lot for reviewing the patches.
I appreciate the very detailed comments. I my reply I omitted the comments, which I agree with and will address in subsequent patches.
Quoted 9 lines · Greg KH
drivers/hv/dxgkrnl/dxgkrnl.h line 100
Quoted 6 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +5
-0+long dxgk_unlocked_ioctl (struct file *f,unsigned int p1,unsigned long p2); + +static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ];Why is the cast needed? Shouldn't you use real types in your structures?
Quoted 4 lines
The VMBus channel ID, which is GUID, is present in the PCI config space of the compute device. The convention is that the lower part of the GUID is LUID (local unique identifier). This function just converts GUID to LUID. I am not sure what is the ask here.
You need to documen the heck out of what you are doing here as it looks very very odd.
Quoted 14 lines
Quoted 4 lines
Quoted 4 lines
+/*
+ * The interface version is used to ensure that the host and the guest use the
+ * same VM bus protocol. It needs to be incremented every time the VM bus
+ * interface changes.DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSIONisQuoted 8 lines
drivers/hv/dxgkrnl/dxgkrnl.h line 117
Quoted 6 lines
+ * incremented each time the earlier versions of the interface are no longer
+ * compatible with the current version.
+ */drivers/hv/dxgkrnl/dxgkrnl.h new file +3
-0+#define DXGK_VMBUS_INTERFACE_VERSION_OLD 27 +#define DXGK_VMBUS_INTERFACE_VERSION 40 +#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16Where do these numbers come from, the hypervisor specification?
Quoted 4 lines
The definitions are for the VMBus interface between the virtual compute device in the guest and the Windows host. The interface version is updated when the VMBus protocol is changed. These are specific to the virtual compute device, not to the hypervisor.
That's not ok, you can not break the user/kernel interface from this moment going forward forever. You can't just have version numbers for your protocol, you need to handle it correctly like all of Linux does.
Quoted 9 lines
Quoted 3 lines
Quoted 1 line
+#define
DXGKRNL_VERSION0x2216What does this mean?
This is the driver implementation version. There are many Microsoft shipped Linux kernels, which include the driver. The version allows to quickly determine, which level of functionality or bug fixes is implemented in the current driver.
That number means nothing once the driver is in the kernel tree as your driver is part of a larger whole and you have no idea what people have, or have not, backported to your portion of the driver or the rest of the kernel anymore. Just drop this, it's not going to be used ever again, and will always be out of date and wrong.
In-kernel drivers do NOT need a version number. I have worked to remove almost all of them, but have not finished that task, which is why you see a few remaining. Do not copy bad examples.
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
+/*
+ * Part of the PCI config space of the vGPU device is used for vGPU
+ * configuration data. Reading/writing of the PCI config space is forwarded
+ * to the host.
+ */
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
+/*
DXGK_VMBUS_INTERFACE_VERSION(u32) */What is this?
This comment explains that the value of
DXGK_VMBUS_INTERFACE_VERSIONis located at the offsetDXGK_VMBUS_CHANNEL_ID_OFFSETin the PCI config space.
Then please explain that.
Quoted 8 lines
Quoted 4 lines
drivers/hv/dxgkrnl/dxgmodule.c line 115
Quoted 2 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +2
-0+#define DXGK_VMBUS_VERSION_OFFSET (DXGK_VMBUS_CHANNEL_ID_OFFSET + \ + sizeof(guid_t))
offsetof()is your friend, please use it.There is no structure definition for the PCI config space of the device. Therefore, offsets are computed by using data size.
That's odd, why not just use a structure on top of the memory location? That way you get real structure information if things change and you don't have to cast anything.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
+/* Luid of the virtual GPU on the host (struct winluid) */
What is a "luid"?
LUID is "Locally Unique Identifier". It is used in Windows and its value is guaranteed to be unique until the computer reboots.
What about vm lifespans? VM cloning? Why does the Linux kernel care about this value?
Quoted 16 lines
Quoted 11 lines
drivers/hv/dxgkrnl/dxgmodule.c line 508
Quoted 8 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +8
-0+ ret =vmbus_driver_register (&dxg_drv); +if (ret) { +pr_err ("vmbus_driver_register failed: %d" , ret); +return ret; + } + dxgglobal->vmbus_registered = true; + +pr_info ("%s Version: %x" , __func__,DXGKRNL_VERSION );When drivers work, they are quiet.
Quoted 3 lines
Also, in-kernel modules do not have a version, they are part of the kernel tree, and that's the "version" they have. You can drop the individual version here, it makes no sense anymore.
Quoted 5 lines
Microsoft develops many Linux kernels when the dxgkrnl driver is included (EFLOW, Android, WSL). The kernels are built at different times and might include a different version of the driver. Printing the version allows to quickly determine what functionality and bug fixes are included in the driver.
Again, see above why your driver version is not needed. Please remove this line as well.
Quoted 2 lines
I see that other in-tree drivers print some information during
init_module(likenfblock.c).
Some older ones do, yes. Please be good and follow the proper rules and be quiet when booting.
Quoted 3 lines
This is done for convenience. So instead of tracking multiple kernel versions, we can track the dxgkrnl driver version. I am ok to remove it if it really hurts something. It is only a single line per driver load.
The driver version _IS_ the kernel version once it is merged into the kernel tree, as you rely on the whole of the kernel for your proper functionality. Drivers do not need individual versions.
Again, work with the experienced Linux developers at your company for this type of thing. They know this already, you don't need me to find basic problems like this in your code :)
thanks,
greg k-h
Wei Liu
maintainerRe: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
In reply to Iouri TarassovI will skip things that are pointed out by Greg.
Quoted 6 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
- Register for PCI and VM bus driver notifications and handle initialization of VM bus channels.
Quoted 9 lines
- Connect the dxgkrnl module to the
drivers/hv/MakefileandKconfig- Create a
MAINTAINERSentryA VM bus channel is a communication interface between the hyper-v guest and the host. The are two type of VM bus channels, used in the driver:
- the global channel
- per virtual compute device channel
Same comment regarding the spelling of VMBus and Hyper-V. Please fix other instances in code and comments.
Quoted 16 lines
A PCI device is created for each virtual compute device, projected by the host. The device vendor is
PCI_VENDOR_ID_MICROSOFTand device id isPCI_DEVICE_ID_VIRTUAL_RENDER.dxg_pci_probe_devicehandles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VM bus channels.VM bus interface version is exchanged by reading/writing the PCI config space of the virtual compute device.
The IO space is used to handle CPU accessible compute device allocations. Hyper-v allocates IO space for the global VM bus channel.
Signed-off-by Iouri Tarassov <[email protected]>---
[...]
drivers/hv/dxgkrnl/dxgkrnl.h line 101
Quoted 4 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ]; +}
This should be moved to the header where luid is defined -- presumably this is useful for other things in the future too.
Also, please provide a comment on why this conversion is okay.
[...]
drivers/hv/dxgkrnl/dxgmodule.c line 143
Quoted 9 lines
+ * A helper function to read PCI config space.
+ */drivers/hv/dxgkrnl/dxgmodule.c new file +7
-0+static int dxg_pci_read_dwords (struct pci_dev *dev,int offset,int size, +void *val) +{ +int off = offset; +int ret; +int i; +
I think you should check for alignment here? size has to be a round number of sizeof(int) otherwise you risk reading cross boundary and causes unintended side effect?
Quoted 32 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +32
-0+for (i =0 ; i < size /sizeof (int ); i++) { + ret =pci_read_config_dword (dev, off, &((int *)val)[i]); +if (ret) { +pr_err ("Failed to read PCI config: %d" , off); +return ret; + } + off +=sizeof (int ); + } +return 0 ; +} + +static int dxg_pci_probe_device (struct pci_dev *dev, +const struct pci_device_id *id) +{ +int ret; +guid_t guid; +u32 vmbus_interface_ver =DXGK_VMBUS_INTERFACE_VERSION ; +struct winluid vgpu_luid = {}; +struct dxgk_vmbus_guestcaps guest_caps = {.wsl2 =1 }; + +mutex_lock (&dxgglobal->device_mutex); + +if (dxgglobal->vmbus_ver ==0 ) { +/* Report capabilities to the host */ + + ret =pci_write_config_dword (dev,DXGK_VMBUS_GUESTCAPS_OFFSET , + guest_caps.guest_caps); +if (ret) + goto cleanup; + +/* Negotiate the VM bus version */ +
[...]
drivers/hv/dxgkrnl/dxgmodule.c line 212
Quoted 3 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +3
-0+pr_debug ("Adapter channel: %pUb\n" , &guid); +pr_debug ("Vmbus interface version: %d\n" , + dxgglobal->vmbus_ver);
No need to wrap the line here.
drivers/hv/dxgkrnl/dxgmodule.c line 214
Quoted 2 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +2
-0+pr_debug ("Host vGPU luid: %x-%x\n" , + vgpu_luid.b, vgpu_luid.a);
Ditto.
Quoted 10 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +10
-0+ +cleanup: + +mutex_unlock (&dxgglobal->device_mutex); + +if (ret) +pr_debug ("err: %s %d" , __func__, ret); +return ret; +} +
[...]
drivers/hv/dxgkrnl/dxgmodule.c line 531
Quoted 10 lines
drivers/hv/dxgkrnl/dxgmodule.c new file +10
-0+static void __exit dxg_drv_exit(void) +{ +dxgglobal_destroy (); +} + +module_init (dxg_drv_init); +module_exit (dxg_drv_exit); + +MODULE_LICENSE ("GPL" ); +MODULE_DESCRIPTION ("Microsoft Dxgkrnl virtual GPU Driver" );
Should be "virtual compute device driver" here? Please be consistent.
Thanks,
Wei.
Re: [PATCH v3 02/30] drivers: hv: dxgkrnl: Driver initialization and loading
Quoted 47 lines · Wei Liu
I will skip things that are pointed out by Greg.
Quoted 6 lines · Iouri Tarassov
- Create skeleton and add basic functionality for the hyper-v compute device driver (dxgkrnl).
- Register for PCI and VM bus driver notifications and handle initialization of VM bus channels.
Quoted 9 lines
- Connect the dxgkrnl module to the
drivers/hv/MakefileandKconfig- Create a
MAINTAINERSentryA VM bus channel is a communication interface between the hyper-v guest and the host. The are two type of VM bus channels, used in the driver:
- the global channel
- per virtual compute device channelSame comment regarding the spelling of VMBus and Hyper-V. Please fix other instances in code and comments.
Quoted 16 lines
A PCI device is created for each virtual compute device, projected by the host. The device vendor is
PCI_VENDOR_ID_MICROSOFTand device id isPCI_DEVICE_ID_VIRTUAL_RENDER.dxg_pci_probe_devicehandles arrival of such devices. The PCI config space of the virtual compute device has luid of the corresponding virtual compute device VM bus channel. This is how the compute device adapter objects are linked to VM bus channels.VM bus interface version is exchanged by reading/writing the PCI config space of the virtual compute device.
The IO space is used to handle CPU accessible compute device allocations. Hyper-v allocates IO space for the global VM bus channel.
Signed-off-by Iouri Tarassov <[email protected]>---
[...]
drivers/hv/dxgkrnl/dxgkrnl.h line 101
Quoted 4 lines
drivers/hv/dxgkrnl/dxgkrnl.h new file +4
-0+static inline void guid_to_luid (guid_t *guid,struct winluid *luid) +{ + *luid = *(struct winluid *)&guid->b[0 ]; +}This should be moved to the header where luid is defined -- presumably this is useful for other things in the future too.
Quoted 2 lines
Also, please provide a comment on why this conversion is okay.
The definition of the structure is in the public header. I do not think it makes sense to move the function there. It is a detail of the internal implementation. There is no official conversion of GUID to LUID.
The comment will be added.
Thanks
Iouri
PATCH v3 3/30 drivers: hv: dxgkrnl: Add VM bus message support, initialize VM bus channels.
In reply to Iouri TarassovImplement support for sending/receiving VM bus messages between the host and the guest.
Initialize the VM bus channels and notify the host about IO space settings of the VM bus global channel.
--- drivers/hv/dxgkrnl/Makefile | 2 +- drivers/hv/dxgkrnl/dxgkrnl.h | 14 ++ drivers/hv/dxgkrnl/dxgmodule.c | 7 + drivers/hv/dxgkrnl/dxgvmbus.c | 413 +++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 86 +++++++ drivers/hv/dxgkrnl/hmgr.h | 75 ++++++ drivers/hv/dxgkrnl/ioctl.c | 24 ++ drivers/hv/dxgkrnl/misc.h | 72 ++++++ include/uapi/misc/d3dkmthk.h | 34 +++ 9 files changed, 726 insertions(+), 1 deletion(-) create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.c create mode 100644 drivers/hv/dxgkrnl/dxgvmbus.h create mode 100644 drivers/hv/dxgkrnl/hmgr.h create mode 100644 drivers/hv/dxgkrnl/ioctl.c create mode 100644 drivers/hv/dxgkrnl/misc.h
drivers/hv/dxgkrnl/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the hyper-v compute device driver (dxgkrnl). obj-$(CONFIG_DXGKRNL) += dxgkrnl.o -dxgkrnl-y := dxgmodule.o +dxgkrnl-y := dxgmodule.o dxgvmbus.o
drivers/hv/dxgkrnl/dxgkrnl.h +14 -0
@@ -29,6 +29,7 @@struct dxgadapter ; +#include "misc.h" #include <uapi/misc/d3dkmthk.h> struct dxgvmbuschannel {
@@ -87,6 +88,13 @@ struct dxgglobal {extern struct dxgglobal *dxgglobal; +int dxgglobal_init_global_channel (void ); +void dxgglobal_destroy_global_channel (void ); +struct vmbus_channel *dxgglobal_get_vmbus (void ); +struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel (void ); +int dxgglobal_acquire_channel_lock (void ); +void dxgglobal_release_channel_lock (void ); +struct dxgprocess {/* Placeholder */ };
@@ -116,4 +124,10 @@ static inline void guid_to_luid(guid_t *guid, struct winluid *luid)#define DXGK_VMBUS_INTERFACE_VERSION 40#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16 +void dxgvmb_initialize (void ); +int dxgvmb_send_set_iospace_region (u64 start,u64 len, +struct vmbus_gpadl *shared_mem_gpadl); + +int ntstatus2int (struct ntstatus status); +#endif
drivers/hv/dxgkrnl/dxgmodule.c +7 -0
@@ -296,6 +296,13 @@ int dxgglobal_init_global_channel(void) goto error; } + ret =dxgvmb_send_set_iospace_region (dxgglobal->mmiospace_base, + dxgglobal->mmiospace_size,0 ); +if (ret <0 ) { +pr_err ("send_set_iospace_region failed" ); + goto error; + } +hv_set_drvdata (dxgglobal->hdev, dxgglobal); dxgglobal->dxgdevice.minor =MISC_DYNAMIC_MINOR ;
drivers/hv/dxgkrnl/dxgvmbus.c new file +413 -0
413 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.h new file +86 -0
86 lines not on this page · raw message
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
@@ -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.h new file +72 -0
72 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +34 -0
@@ -14,6 +14,40 @@ #ifndef _D3DKMTHK_H #define _D3DKMTHK_H +/* + * This structure matches the definition of D3DKMTHANDLE in Windows. + * The handle is opaque in user mode. It is used by user mode applications to + * represent kernel mode objects, created by dxgkrnl. + */ +struct d3dkmthandle { + union { + struct { + __u32 instance : 6; + __u32 index : 24; + __u32 unique : 2; + }; + __u32 v; + }; +}; + +/* + * VM bus messages return Windows' NTSTATUS, which is integer and only negative + * value indicates a failure. A positive number is a success and needs to be + * returned to user mode as the IOCTL return code. Negative status codes are + * converted to Linux error codes. + */ +struct ntstatus { + union { + struct { + int code : 16; + int facility : 13; + int customer : 1; + int severity : 2; + }; + int v; + }; +}; + /* Matches Windows LUID definition */ struct winluid { __u32 a;
Signature · 1 line
2.35.1
Wei Liu
maintainerRe: [PATCH v3 03/30] drivers: hv: dxgkrnl: Add VM bus message support, initialize VM bus channels.
The subject line is too long. Also, no period at the end please.
You can write it as:
drivers: hv: dxgkrnl: Add VMBus message support and initialize channels
On Tue, Mar 01, 2022 at 11:45:50AM -0800, Iouri Tarassov wrote:
[...]
Quoted 4 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +4
-0+ +struct dxgvmbusmsgres { +/* Points to the allocated buffer */ +struct dxgvmb_ext_header *hdr;
drivers/hv/dxgkrnl/dxgvmbus.c line 77
Quoted 10 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +10
-0+/* Points to dxgkvmb_command_vm_to_host or dxgkvmb_command_vgpu_to_host */ +void *msg; +/* The vm bus channel, used to pass the message to the host */ +struct dxgvmbuschannel *channel; +/* Message size in bytes including the header, the payload and the result */ +u32 size; +/* Result buffer size in bytes */ +u32 res_size; +/* Points to the result within the allocated buffer */ +void *res;
Please align the comments with their fields.
Quoted 2 lines
(quoted diff) +2
-0+}; +
[...]
drivers/hv/dxgkrnl/dxgvmbus.c line 220
Quoted 12 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +12
-0+static void process_inband_packet (struct dxgvmbuschannel *channel, +struct vmpacket_descriptor *desc) +{ +u32 packet_length =hv_pkt_datalen (desc); +struct dxgkvmb_command_host_to_vm *packet; + +if (packet_length <sizeof (struct dxgkvmb_command_host_to_vm )) { +pr_err ("Invalid global packet" ); + }else { + packet =hv_pkt_data (desc); +pr_debug ("global packet %d" , + packet->command_type);
Unnecessary line wrap.
Quoted 13 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +13
-0+switch (packet->command_type) { +case DXGK_VMBCOMMAND_SIGNALGUESTEVENT : +case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE : +break ; +case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION : +break ; +default : +pr_err ("unexpected host message %d" , + packet->command_type); + } + } +} +
[...]
Quoted 7 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +7
-0+ +/* Receive callback for messages from the host */ +void dxgvmbuschannel_receive (void *ctx) +{ +struct dxgvmbuschannel *channel = ctx; +struct vmpacket_descriptor *desc; +u32 packet_length =0 ;
drivers/hv/dxgkrnl/dxgvmbus.c line 286
Quoted 10 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +10
-0+ + foreach_vmbus_pkt(desc, channel->channel) { + packet_length =hv_pkt_datalen (desc); +pr_debug ("next packet (id, size, type): %llu %d %d" , + desc->trans_id, packet_length, desc->type); +if (desc->type ==VM_PKT_COMP ) { +process_completion_packet (channel, desc); + }else { +if (desc->type !=VM_PKT_DATA_INBAND ) +pr_err ("unexpected packet type" );
This can potentially flood the guest if the backend is misbehaving. We've seen flooding before so would definitely not want more of it. Please consider using the ratelimit version pr_err.
The same comment goes for all other pr calls in repeatedly called paths. I can see the value of having precise output from the pr_debug a few lines above though.
Quoted 6 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +6
-0+else +process_inband_packet (channel, desc); + } + } +} +
[...]
Quoted 12 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +12
-0+int dxgvmb_send_set_iospace_region (u64 start,u64 len, +struct vmbus_gpadl *shared_mem_gpadl) +{ +int ret; +struct dxgkvmb_command_setiospaceregion *command; +struct dxgvmbusmsg msg; + + ret =init_message (&msg,NULL ,sizeof (*command)); +if (ret) +return ret; + command = (void *)msg.msg; +
drivers/hv/dxgkrnl/dxgvmbus.c line 400
Quoted 10 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +10
-0+ ret =dxgglobal_acquire_channel_lock (); +if (ret <0 ) + goto cleanup; + +command_vm_to_host_init1 (&command->hdr, +DXGK_VMBCOMMAND_SETIOSPACEREGION ); + command->start = start; + command->length = len; +if (command->shared_page_gpadl) + command->shared_page_gpadl = shared_mem_gpadl->gpadl_handle;
shared_mem_gpadl should be checked to be non-null. There is at least one call site passes 0 to it.
Quoted 13 lines
drivers/hv/dxgkrnl/dxgvmbus.c new file +13
-0+ ret =dxgvmb_send_sync_msg_ntstatus (&dxgglobal->channel, msg.hdr, + msg.size); +if (ret <0 ) +pr_err ("send_set_iospace_region failed %x" , ret); + +dxgglobal_release_channel_lock (); +cleanup: +free_message (&msg,NULL ); +if (ret) +pr_debug ("err: %s %d" , __func__, ret); +return ret; +} +
[...]
Quoted 7 lines
drivers/hv/dxgkrnl/misc.h new file +7
-0+ + +#define NT_SUCCESS (status) (status.v >= 0) + +#ifndef DEBUG + +#define DXGKRNL_ASSERT (exp)
drivers/hv/dxgkrnl/misc.h line 68
Quoted 10 lines
drivers/hv/dxgkrnl/misc.h new file +10
-0+ +#else + +#define DXGKRNL_ASSERT (exp) \ +do { \ + if (!(exp)) { \ + dump_stack(); \ + BUG_ON(true); \ + } \ +} while (0)
You can just use BUG_ON(exp), right? BUG_ON calls panic, which already dumps the stack when CONFIG_DEBUG_VERBOSE is set.
Thanks,
Wei.
PATCH v3 4/30 drivers: hv: dxgkrnl: Creation of dxgadapter object
In reply to Iouri TarassovHandle creation and destruction of dxgadapter object, which represents a virtual compute device, projected to the VM by the host. The dxgadapter object is created when the corresponding VM bus channel is offered by Hyper-V.
There could be multiple virtual compute device objects, projected by the host to VM. They are enumerated by issuing IOCTLs to the /dev/dxg device.
The adapter object can start functioning only when the global VM bus channel and the corresponding per device VM bus channel are initialized. Notifications about arrival of a virtual compute 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 waiting dxgadapter objects are maintained. When dxgkrnl is notified about a VM bus channel arrival, if tries to start all adapters, which are not started yet.
Properties of the adapter object are determined by sending VM bus messages to the host to the corresponding VM bus channel.
When the per virtual compute device VM bus channel or the global channel are destroyed, the adapter object is destroyed.
--- drivers/hv/dxgkrnl/Makefile | 2 +- drivers/hv/dxgkrnl/dxgadapter.c | 172 +++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 89 +++++++++++++ drivers/hv/dxgkrnl/dxgmodule.c | 200 ++++++++++++++++++++++++++++- drivers/hv/dxgkrnl/dxgvmbus.c | 216 +++++++++++++++++++++++++++++--- drivers/hv/dxgkrnl/dxgvmbus.h | 128 +++++++++++++++++++ drivers/hv/dxgkrnl/hmgr.h | 75 ----------- drivers/hv/dxgkrnl/misc.c | 37 ++++++ drivers/hv/dxgkrnl/misc.h | 17 +++ 9 files changed, 839 insertions(+), 97 deletions(-) create mode 100644 drivers/hv/dxgkrnl/dxgadapter.c delete mode 100644 drivers/hv/dxgkrnl/hmgr.h create mode 100644 drivers/hv/dxgkrnl/misc.c
drivers/hv/dxgkrnl/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the hyper-v compute device driver (dxgkrnl). obj-$(CONFIG_DXGKRNL) += dxgkrnl.o -dxgkrnl-y := dxgmodule.o dxgvmbus.o +dxgkrnl-y := dxgmodule.o misc.o dxgadapter.o ioctl.o dxgvmbus.o
drivers/hv/dxgkrnl/dxgadapter.c new file +172 -0
172 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgkrnl.h +89 -0
122 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgmodule.c +199 -1
261 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.c +196 -20
277 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.h +128 -0
144 lines not on this page · raw message
drivers/hv/dxgkrnl/hmgr.h deleted +0 -75
75 lines not on this page · raw message
drivers/hv/dxgkrnl/misc.c new file +37 -0
@@ -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 +17 -0
@@ -14,6 +14,9 @@#ifndef _MISC_H_#define _MISC_H_ +/* Max characters in Windows path */ +#define WIN_MAX_PATH 260 +extern const struct d3dkmthandle zerohandle;/*
@@ -23,9 +26,23 @@ extern const struct d3dkmthandle zerohandle;* When a lower lock ois held, the higher lock should not be acquired. * * channel_lock +* fd_mutex +* plistmutex +* table_lock +* core_lock +* device_lock +* process->process_mutex +* adapter_list_lock * device_mutex */ +u16 *wcsncpy (u16 *dest,const u16 *src,size_t n); + +enum dxglockstate { +DXGLOCK_SHARED , +DXGLOCK_EXCL +}; +/* * Some of the Windows return codes, which needs to be translated to Linux * IOCTL return codes. Positive values are success codes and need to be
Signature · 1 line
2.35.1
Wei Liu
maintainerRe: [PATCH v3 04/30] drivers: hv: dxgkrnl: Creation of dxgadapter object
On Tue, Mar 01, 2022 at 11:45:51AM -0800, Iouri Tarassov wrote:
[...]
Quoted 9 lines
drivers/hv/dxgkrnl/dxgadapter.c new file +9
-0+int dxgadapter_set_vmbus (struct dxgadapter *adapter,struct hv_device *hdev) +{ +int ret; + +guid_to_luid (&hdev->channel->offermsg.offer.if_instance, + &adapter->luid); +pr_debug ("%s: %x:%x %p %pUb\n" , + __func__, adapter->luid.b, adapter->luid.a, hdev->channel, + &hdev->channel->offermsg.offer.if_instance);
drivers/hv/dxgkrnl/dxgadapter.c line 42
Quoted 10 lines
drivers/hv/dxgkrnl/dxgadapter.c new file +10
-0+ + ret =dxgvmbuschannel_init (&adapter->channel, hdev); +if (ret) + goto cleanup; + + adapter->channel.adapter = adapter; + adapter->hv_dev = hdev; + + ret =dxgvmb_send_open_adapter (adapter); +if (ret <0 ) {
if (ret) is simpler?
Please be consistent regarding how you check for errors.
Quoted 16 lines
drivers/hv/dxgkrnl/dxgadapter.c new file +16
-0+pr_err ("dxgvmb_send_open_adapter failed: %d\n" , ret); + goto cleanup; + } + + ret =dxgvmb_send_get_internal_adapter_info (adapter); +if (ret <0 ) +pr_err ("get_internal_adapter_info failed: %d" , ret); + +cleanup: +if (ret) +pr_debug ("err: %s %d" , __func__, ret); +return ret; +} + +void dxgadapter_start (struct dxgadapter *adapter) +{
drivers/hv/dxgkrnl/dxgadapter.c line 68
Quoted 10 lines
drivers/hv/dxgkrnl/dxgadapter.c new file +10
-0+struct dxgvgpuchannel *ch =NULL ; +struct dxgvgpuchannel *entry; +int ret; + +pr_debug ("%s %x-%x" , + __func__, adapter->luid.a, adapter->luid.b); + +/* Find the corresponding vGPU vm bus channel */ +list_for_each_entry (entry, &dxgglobal->vgpu_ch_list_head, + vgpu_ch_list_entry) {
The mutex is not acquired in this function.
I have not checked if this function is used elsewhere. But this is a non-static function, it should have at least a comment on the locking requirement?
If it is not needed elsewhere, please make it static or named it dxgadapter_start_locked.
[...]
drivers/hv/dxgkrnl/dxgadapter.c line 103
Quoted 3 lines
drivers/hv/dxgkrnl/dxgadapter.c new file +3
-0+} + +void dxgadapter_stop (struct dxgadapter *adapter)
Same comment applies to this function as well.
Thanks,
Wei.
PATCH v3 5/30 drivers: hv: dxgkrnl: Opening of /dev/dxg device and dxgprocess creation
In reply to Iouri Tarassov- Implement opening of the device (/dev/dxg) file object and creation of dxgprocess objects.
- Add VM bus messages to create and destroy the host side of a dxgprocess object.
- Implement the handle manager, which manages d3dkmthandle handles for the internal process objects. The handles are used by a user mode client to reference dxgkrnl objects.
dxgprocess is created for each process, which opens /dev/dxg. dxgprocess is ref counted, so the existing dxgprocess objects is used for a process, which opens the device object multiple time. dxgprocess is destroyed when the file object is released.
A corresponding dxgprocess object is created on the host for every dxgprocess object in the guest.
When a dxgkrnl object is created, in most cases the corresponding object is created in the host. The VM references the host objects by handles (d3dkmthandle). d3dkmthandle values for a host object and the corresponding VM object are the same. A host handle is allocated first and its value is assigned to the guest object.
--- drivers/hv/dxgkrnl/Makefile | 2 +- drivers/hv/dxgkrnl/dxgkrnl.h | 40 ++- drivers/hv/dxgkrnl/dxgmodule.c | 67 +++- drivers/hv/dxgkrnl/dxgprocess.c | 97 ++++++ drivers/hv/dxgkrnl/dxgvmbus.c | 79 +++++ drivers/hv/dxgkrnl/dxgvmbus.h | 24 ++ drivers/hv/dxgkrnl/hmgr.c | 566 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/hmgr.h | 112 +++++++ drivers/hv/dxgkrnl/ioctl.c | 70 ++++ drivers/hv/dxgkrnl/misc.h | 1 - include/uapi/misc/d3dkmthk.h | 2 + 11 files changed, 1056 insertions(+), 4 deletions(-) create mode 100644 drivers/hv/dxgkrnl/dxgprocess.c create mode 100644 drivers/hv/dxgkrnl/hmgr.c create mode 100644 drivers/hv/dxgkrnl/hmgr.h
drivers/hv/dxgkrnl/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the hyper-v compute device driver (dxgkrnl). obj-$(CONFIG_DXGKRNL) += dxgkrnl.o -dxgkrnl-y := dxgmodule.o misc.o dxgadapter.o ioctl.o dxgvmbus.o +dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
drivers/hv/dxgkrnl/dxgkrnl.h +39 -1
@@ -27,9 +27,11 @@#include <linux/pci.h> #include <linux/hyperv.h> +struct dxgprocess ;struct dxgadapter ;#include "misc.h" +#include "hmgr.h" #include <uapi/misc/d3dkmthk.h> struct dxgk_device_types {
@@ -137,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 ,
@@ -210,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 new file +97 -0
97 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 +24 -0
@@ -14,7 +14,11 @@#ifndef _DXGVMBUS_H#define _DXGVMBUS_H +struct dxgprocess ; +struct dxgadapter ; +#define DXG_MAX_VM_BUS_PACKET_SIZE (1024 * 128) +#define DXG_VM_PROCESS_NAME_LENGTH 260enum dxgkvmb_commandchanneltype { DXGKVMB_VGPU_TO_HOST,
@@ -169,6 +173,26 @@ struct dxgkvmb_command_setiospaceregion {u32 shared_page_gpadl; }; +struct dxgkvmb_command_createprocess { +struct dxgkvmb_command_vm_to_host hdr; +void *process; +u64 process_id; +u16 process_name[DXG_VM_PROCESS_NAME_LENGTH +1 ]; +u8 csrss_process:1 ; +u8 dwm_process:1 ; +u8 wow64_process:1 ; +u8 linux_process:1 ; +}; + +struct dxgkvmb_command_createprocess_return { +struct d3dkmthandle hprocess; +}; + +// The command returns ntstatus +struct dxgkvmb_command_destroyprocess { +struct dxgkvmb_command_vm_to_host hdr; +}; +struct dxgkvmb_command_openadapter {struct dxgkvmb_command_vgpu_to_host hdr;u32 vmbus_interface_version;
drivers/hv/dxgkrnl/hmgr.c new file +566 -0
566 lines not on this page · raw message
drivers/hv/dxgkrnl/hmgr.h new file +112 -0
112 lines not on this page · raw message
drivers/hv/dxgkrnl/ioctl.c +70 -0
73 lines not on this page · raw message
drivers/hv/dxgkrnl/misc.h +0 -1
@@ -31,7 +31,6 @@ extern const struct d3dkmthandle zerohandle;* table_lock * core_lock * device_lock -* process->process_mutex * adapter_list_lock * device_mutex */
include/uapi/misc/d3dkmthk.h +2 -0
@@ -54,4 +54,6 @@ struct winluid { __u32 b; }; +#define LX_IO_MAX 0x45 +#endif /* _D3DKMTHK_H */
Signature · 1 line
2.35.1
Re: [PATCH v3 05/30] drivers: hv: dxgkrnl: Opening of /dev/dxg device and dxgprocess creation
drivers/hv/dxgkrnl/dxgkrnl.h line 30
Quoted 7 lines · Iouri Tarassov
drivers/hv/dxgkrnl/dxgkrnl.h +1
-0@@ -27,9 +27,11 @@#include <linux/pci.h> #include <linux/hyperv.h> +struct dxgprocess ;
No need to pre-define this.
thanks,
greg k-h
Re: [PATCH v3 05/30] drivers: hv: dxgkrnl: Opening of /dev/dxg device and dxgprocess creation
In reply to Iouri TarassovQuoted 1 line · Iouri Tarassov
+#define
LX_IO_MAX0x45
What does that mean???
Wei Liu
maintainerRe: [PATCH v3 05/30] drivers: hv: dxgkrnl: Opening of /dev/dxg device and dxgprocess creation
In reply to Iouri TarassovQuoted 2 lines · Iouri Tarassov
- Implement opening of the device (
/dev/dxg) file object and creation of dxgprocess objects.
[...]
Quoted 11 lines
static int
dxgk_open(struct inode *n, struct file *f){drivers/hv/dxgkrnl/dxgmodule.c +8
-1-return 0 ; +int ret =0 ; +struct dxgprocess *process; + +pr_debug ("%s %p %d %d" , + __func__, f, current->pid, current->tgid); + + +/* Find/create a dxgprocess structure for this process */
drivers/hv/dxgkrnl/dxgmodule.c static void dxgglobal_stop_adapters(void) · line 264
Quoted 10 lines
drivers/hv/dxgkrnl/dxgmodule.c +10
-0+ process =dxgglobal_get_current_process (); + +if (process) { + f->private_data = process; + }else { +pr_debug ("cannot create dxgprocess for open\n" ); + ret = -EBADF ; + } + +pr_debug ("%s end %x" , __func__, ret);
I would normally remove pr_deubg's like this when submitting. It doesn't provide much information.
Quoted 3 lines
drivers/hv/dxgkrnl/dxgmodule.c +1
-0+return ret; }
[...]
Quoted 20 lines
drivers/hv/dxgkrnl/dxgvmbus.c +19
-0+int dxgvmb_send_create_process (struct dxgprocess *process) +{ +int ret; +struct dxgkvmb_command_createprocess *command; +struct dxgkvmb_command_createprocess_return result = {0 }; +struct dxgvmbusmsg msg; +char s[WIN_MAX_PATH ]; +int i; + + ret =init_message (&msg,NULL , process,sizeof (*command)); +if (ret) +return ret; + command = (void *)msg.msg; + + ret =dxgglobal_acquire_channel_lock (); +if (ret <0 ) + goto cleanup; + +command_vm_to_host_init1 (&command->hdr,DXGK_VMBCOMMAND_CREATEPROCESS );
drivers/hv/dxgkrnl/dxgvmbus.c int dxgvmb_send_set_iospace_region(u64 start, u64 len, · line 526
Quoted 10 lines
drivers/hv/dxgkrnl/dxgvmbus.c +10
-0+ command->process = process; + command->process_id = process->process->pid; + command->linux_process =1 ; + s[0 ] =0 ; +__get_task_comm (s,WIN_MAX_PATH , process->process); +for (i =0 ; i <WIN_MAX_PATH ; i++) { + command->process_name[i] = s[i]; +if (s[i] ==0 ) +break ; + }
What's wrong with doing
__get_task_comm(command->process_name, WIN_MAX_PATH, process->process);
here?
That saves you many bytes on stack.
[...]
drivers/hv/dxgkrnl/ioctl.c line 37
Quoted 5 lines
drivers/hv/dxgkrnl/ioctl.c +5
-0+static char *errorstr (int ret) +{ +return ret <0 ?"err" :"" ; +} +
This is not used in this patch.
[...]
drivers/hv/dxgkrnl/misc.h extern const struct d3dkmthandle zerohandle; · line 34
Quoted 9 lines
drivers/hv/dxgkrnl/misc.h +0
-1@@ -31,7 +31,6 @@ extern const struct d3dkmthandle zerohandle;* table_lock * core_lock * device_lock -* process->process_mutex
Why is this deleted?
Thanks,
Wei.
PATCH v3 6/30 drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects
In reply to Iouri TarassovImplement ioctls to enumerate dxgadapter objects:
- The LX_DXENUMADAPTERS2 ioctl
- The LX_DXENUMADAPTERS3 ioctl.
Implement ioctls to open adapter by luid and to close adapter handle:
- The LX_DXOPENADAPTERFROMLUID ioctl
- the LX_DXCLOSEADAPTER ioctl
Impllement the ioctl to query dxgadapter information:
- The LX_DXQUERYADAPTERINFO ioctl
When a dxgadapter is enumerated, it is implicitely opened and a handle (d3dkmthandle) is created in the current process handle table. The handle is returned to the caller and can be used by user mode to reference the adapter object in other ioctls.
The caller is responsible for closing the adapter when it is not longer used by issuing the LX_DXCLOSEADAPTER ioctl.
A dxgprocess has a list of opened dxgadapter objects (dxgprocess_adapter is used to represent the entry in the list). A dxgadapter also has a list of dxgprocess_adapter objects. This is needed for cleanup because either a process or an adapter could be destroyed first.
--- 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/dxgvmbus.h | 12 + drivers/hv/dxgkrnl/ioctl.c | 412 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/misc.h | 1 + include/uapi/misc/d3dkmthk.h | 103 ++++++++ 9 files changed, 914 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +77 -0
@@ -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
@@ -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/dxgvmbus.h +12 -0
@@ -235,4 +235,16 @@ struct dxgkvmb_command_getinternaladapterinfo_return { struct winluid host_vgpu_luid; }; +struct dxgkvmb_command_queryadapterinfo { +struct dxgkvmb_command_vgpu_to_host hdr; +enum kmtqueryadapterinfotype query_type; +u32 private_data_size; +u8 private_data[1 ]; +}; + +struct dxgkvmb_command_queryadapterinfo_return { +struct ntstatus status; +u8 private_data[1 ]; +}; +#endif /* _DXGVMBUS_H */
drivers/hv/dxgkrnl/ioctl.c +412 -0
422 lines not on this page · raw message
drivers/hv/dxgkrnl/misc.h +1 -0
@@ -31,6 +31,7 @@ extern const struct d3dkmthandle zerohandle;* table_lock * core_lock * device_lock +* process_adapter_mutex * adapter_list_lock * device_mutex */
include/uapi/misc/d3dkmthk.h +103 -0
109 lines not on this page · raw message
Signature · 1 line
2.35.1
Wei Liu
maintainerRe: [PATCH v3 06/30] drivers: hv: dxgkrnl: Enumerate and open dxgadapter objects
On Tue, Mar 01, 2022 at 11:45:53AM -0800, Iouri Tarassov wrote:
[...]
drivers/hv/dxgkrnl/dxgadapter.c bool dxgadapter_is_active(struct dxgadapter *adapter) · line 162
Quoted 4 lines
drivers/hv/dxgkrnl/dxgadapter.c +4
-0+void dxgadapter_remove_process (struct dxgprocess_adapter *process_info) +{ +pr_debug ("%s %p %p" , __func__, + process_info->adapter, process_info);
This is not very useful in a production system.
Keep in mind that this can flood dmesg when the debug level is cranked up. The user is just perhaps trying to get information for other parts of the kernel.
I would like to ask you to reduce the amount of pr_debug's in code, only leave the most critical ones in place. There is ftrace and ebfp in the kernel to help with observation at runtime.
drivers/hv/dxgkrnl/dxgadapter.c bool dxgadapter_is_active(struct dxgadapter *adapter) · line 165
Quoted 3 lines
drivers/hv/dxgkrnl/dxgadapter.c +3
-0+list_del (&process_info->adapter_process_list_entry); + process_info->adapter_process_list_entry.next =NULL ; + process_info->adapter_process_list_entry.prev =NULL ;
There is no need to explicitly set next and prev pointers to NULL. They have been set to poison values by list_del. Please remove this kind of code from all other places.
Quoted 10 lines
drivers/hv/dxgkrnl/dxgadapter.c +3
-0+} +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); } +
[...]
drivers/hv/dxgkrnl/dxgprocess.c void dxgprocess_release(struct kref *refcount) · line 112
Quoted 4 lines
drivers/hv/dxgkrnl/dxgprocess.c +4
-0+struct dxgprocess_adapter *dxgprocess_get_adapter_info (struct dxgprocess + *process, +struct dxgadapter + *adapter)
Please document the locking requirement or renamed this function. I see the list is manipulated with no lock held.
drivers/hv/dxgkrnl/dxgprocess.c void dxgprocess_release(struct kref *refcount) · line 124
Quoted 12 lines
drivers/hv/dxgkrnl/dxgprocess.c +12
-0+{ +struct dxgprocess_adapter *entry; + +list_for_each_entry (entry, &process->process_adapter_list_head, + process_adapter_list_entry) { +if (adapter == entry->adapter) { +pr_debug ("Found process info %p" , entry); +return entry; + } + } +return NULL ; +}
Thanks,
Wei.
PATCH v3 7/30 drivers: hv: dxgkrnl: Creation of dxgdevice objects
In reply to Iouri TarassovImplement ioctls for creation and destruction of dxgdevice objects:
- the LX_DXCREATEDEVICE ioctl
- the LX_DXDESTROYDEVICE ioctl
A dxgdevice object represents a container of other virtual compute device objects (allocations, sync objects, contexts, etc.). It belongs to a dxgadapter object.
--- drivers/hv/dxgkrnl/dxgadapter.c | 187 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 58 ++++++++++ drivers/hv/dxgkrnl/dxgprocess.c | 43 ++++++++ drivers/hv/dxgkrnl/dxgvmbus.c | 80 ++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 22 ++++ drivers/hv/dxgkrnl/ioctl.c | 134 +++++++++++++++++++++++ drivers/hv/dxgkrnl/misc.h | 1 + include/uapi/misc/d3dkmthk.h | 82 ++++++++++++++ 8 files changed, 607 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +187 -0
@@ -199,6 +199,121 @@ 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); + device->adapter =NULL ; + } + +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 +328,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 +343,35 @@ 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); +dxgvmb_send_flush_device (device, +DXGDEVICE_FLUSHSCHEDULER_DEVICE_TERMINATE ); +dxgdevice_destroy (device); +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 +389,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 +58 -0
106 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 +80 -0
86 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.h +22 -0
@@ -247,4 +247,26 @@ struct dxgkvmb_command_queryadapterinfo_return { u8 private_data[1]; }; +struct dxgkvmb_command_createdevice { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_createdeviceflags flags; +bool cdd_device; +void *error_code; +}; + +struct dxgkvmb_command_createdevice_return { +struct d3dkmthandle device; +}; + +struct dxgkvmb_command_destroydevice { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +}; + +struct dxgkvmb_command_flushdevice { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +enum dxgdevice_flushschedulerreason reason; +}; +#endif /* _DXGVMBUS_H */
drivers/hv/dxgkrnl/ioctl.c +134 -0
152 lines not on this page · raw message
drivers/hv/dxgkrnl/misc.h +1 -0
@@ -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
include/uapi/misc/d3dkmthk.h +82 -0
106 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 8/30 drivers: hv: dxgkrnl: Creation of dxgcontext objects
In reply to Iouri TarassovImplement ioctls for creation/destruction of dxgcontext objects:
- the LX_DXCREATECONTEXTVIRTUAL ioctl
- the LX_DXDESTROYCONTEXT ioctl.
A dxgcontext object represents a compute device execution thread. Ccompute device DMA buffers and synchronization operations are submitted for execution to a dxgcontext. dxgcontexts objects belong to a dxgdevice object.
--- drivers/hv/dxgkrnl/dxgadapter.c | 102 +++++++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 38 +++++++ drivers/hv/dxgkrnl/dxgprocess.c | 4 + drivers/hv/dxgkrnl/dxgvmbus.c | 102 ++++++++++++++++++- drivers/hv/dxgkrnl/dxgvmbus.h | 18 ++++ drivers/hv/dxgkrnl/ioctl.c | 172 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/misc.h | 1 + include/uapi/misc/d3dkmthk.h | 47 +++++++++ 8 files changed, 483 insertions(+), 1 deletion(-)
drivers/hv/dxgkrnl/dxgadapter.c +102 -0
@@ -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) {
@@ -306,6 +322,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;
@@ -314,6 +356,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
@@ -30,6 +30,7 @@struct dxgprocess ;struct dxgadapter ;struct dxgdevice ; +struct dxgcontext ;#include "misc.h" #include "hmgr.h"
@@ -285,6 +286,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 {
@@ -298,6 +300,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;
@@ -312,7 +316,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);
@@ -355,6 +385,14 @@ int dxgvmb_send_destroy_device(struct dxgadapter *adapter, struct d3dkmthandle h);int dxgvmb_send_flush_device (struct dxgdevice *device,enum dxgdevice_flushschedulerreason reason); +struct d3dkmthandle +dxgvmb_send_create_context (struct dxgadapter *adapter, +struct dxgprocess *process, +struct d3dkmt_createcontextvirtual + *args); +int dxgvmb_send_destroy_context (struct dxgadapter *adapter, +struct dxgprocess *process, +struct d3dkmthandle h);int dxgvmb_send_query_adapter_info (struct dxgprocess *process,struct dxgadapter *adapter,struct d3dkmt_queryadapterinfo *args);
drivers/hv/dxgkrnl/dxgprocess.c +4 -0
@@ -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 +101 -1
114 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.h +18 -0
@@ -269,4 +269,22 @@ struct dxgkvmb_command_flushdevice { enum dxgdevice_flushschedulerreason reason; }; +struct dxgkvmb_command_createcontextvirtual { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle context; +struct d3dkmthandle device; +u32 node_ordinal; +u32 engine_affinity; +struct d3dddi_createcontextflags flags; +enum d3dkmt_clienthint client_hint; +u32 priv_drv_data_size; +u8 priv_drv_data[1 ]; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroycontext { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle context; +}; +#endif /* _DXGVMBUS_H */
drivers/hv/dxgkrnl/ioctl.c +172 -0
184 lines not on this page · raw message
drivers/hv/dxgkrnl/misc.h +1 -0
@@ -30,6 +30,7 @@ extern const struct d3dkmthandle zerohandle;* fd_mutex * plistmutex * table_lock +* context_list_lock * core_lock * device_lock * process_adapter_mutex
include/uapi/misc/d3dkmthk.h +47 -0
59 lines not on this page · raw message
Signature · 1 line
2.35.1
Wei Liu
maintainerRe: [PATCH v3 08/30] drivers: hv: dxgkrnl: Creation of dxgcontext objects
On Tue, Mar 01, 2022 at 11:45:55AM -0800, Iouri Tarassov wrote:
[...]
Quoted 7 lines
drivers/hv/dxgkrnl/ioctl.c +7
-0+static int +dxgk_create_context_virtual (struct dxgprocess *process,void *__user inargs) +{ +struct d3dkmt_createcontextvirtual args; +int ret; +struct dxgadapter *adapter =NULL ; +struct dxgdevice *device =NULL ;
drivers/hv/dxgkrnl/ioctl.c dxgk_destroy_device(struct dxgprocess *process, void *__user inargs) · line 586
Quoted 10 lines
drivers/hv/dxgkrnl/ioctl.c +10
-0+struct dxgcontext *context =NULL ; +struct d3dkmthandle host_context_handle = {}; +bool device_lock_acquired = false; + +pr_debug ("ioctl: %s" , __func__); + + ret =copy_from_user (&args, inargs,sizeof (args)); +if (ret) { +pr_err ("%s failed to copy input args" , __func__); + ret = -EINVAL ;
This should be -EFAULT. This goes for other copy_from_user calls too. You can also drop the pr_err above.
Thanks,
Wei.
PATCH v3 9/30 drivers: hv: dxgkrnl: Creation of compute device allocations and resources
In reply to Iouri TarassovImplemented ioctls to create and destroy virtual compute device allocations (dxgallocation) and resources (dxgresource):
- the LX_DXCREATEALLOCATION ioctl,
- the LX_DXDESTROYALLOCATION2 ioctl.
Compute device allocations (dxgallocation objects) represent memory allocation, which could be accessible by the device. Allocations can be created around existing system memory (provided by an application) or memory, allocated by dxgkrnl on the host.
Compute device resources (dxgresource objects) represent containers of compute device allocations. Allocations could be dynamically added, removed from a resource.
Each allocation/resource has associated driver private data, which is provided during creation.
Each created resource or allocation have a handle (d3dkmthandle), which is used to reference the corresponding object in other ioctls.
A dxgallocation can be resident (meaning that it is accessible by the compute device) or evicted. When an allocation is evicted, its content is stored in the backing store in system memory.
--- 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/dxgvmbus.h | 123 ++++++ drivers/hv/dxgkrnl/ioctl.c | 637 +++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/misc.h | 3 + include/uapi/misc/d3dkmthk.h | 204 ++++++++++ 8 files changed, 1996 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +274 -0
@@ -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;
@@ -332,6 +372,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);
@@ -348,6 +408,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;
@@ -416,6 +630,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
@@ -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/dxgvmbus.h +123 -0
135 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
@@ -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
include/uapi/misc/d3dkmthk.h +204 -0
224 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 10/30 drivers: hv: dxgkrnl: Creation of compute device sync objects
In reply to Iouri TarassovImplement ioctls to create and destroy compute devicesync objects:
- the LX_DXCREATESYNCHRONIZATIONOBJECT ioctl,
- the LX_DXDESTROYSYNCHRONIZATIONOBJECT ioctl.
Compute device synchronization objects are used to synchronize execution of compute device commands, which are queued to different execution contexts (dxgcontext objects).
There are several types of sync objects (mutex, monitored fence, CPU event, fence). A "signal" or a "wait" operation could be queued to an execution context.
Monitored fence sync objects are particular important.
A monitored fence object has a fence value, which could be monitored by the compute device or by CPU. Therefore, a CPU virtual address is allocated during object creation to allow an application to read the fence value. dxg_map_iospace and dxg_unmap_iospace implement creation of the CPU virtual address. This is done as follow:
- The host allocates a portion of the guest IO space, which is mapped to the actual fence value memory on the host
- The host returns the guest IO space address to the guest
- The guest allocates a CPU virtual address and updates page tables to point to the IO space address
--- drivers/hv/dxgkrnl/dxgadapter.c | 182 +++++++++++++++++++++++++++++ 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/dxgvmbus.h | 20 ++++ drivers/hv/dxgkrnl/ioctl.c | 130 +++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 95 +++++++++++++++ 8 files changed, 723 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +182 -0
@@ -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;
@@ -570,6 +610,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 ));
@@ -810,3 +874,121 @@ 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) { +pr_err ("%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
@@ -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
@@ -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/dxgvmbus.h +20 -0
@@ -410,4 +410,24 @@ struct dxgkvmb_command_destroycontext { struct d3dkmthandle context; }; +struct dxgkvmb_command_createsyncobject { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_createsynchronizationobject2 args; +u32 client_hint; +}; + +struct dxgkvmb_command_createsyncobject_return { +struct d3dkmthandle sync_object; +struct d3dkmthandle global_sync_object; +u64 fence_gpu_va; +u64 fence_storage_address; +u32 fence_storage_offset; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroysyncobject { +struct dxgkvmb_command_vm_to_host hdr; +struct d3dkmthandle sync_object; +}; +#endif /* _DXGVMBUS_H */
drivers/hv/dxgkrnl/ioctl.c +130 -0
148 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +95 -0
113 lines not on this page · raw message
Signature · 1 line
2.35.1
Wei Liu
maintainerRe: [PATCH v3 10/30] drivers: hv: dxgkrnl: Creation of compute device sync objects
On Tue, Mar 01, 2022 at 11:45:57AM -0800, Iouri Tarassov wrote:
[...]
drivers/hv/dxgkrnl/dxgadapter.c void dxgadapter_remove_process(struct dxgprocess_adapter *process_info) · line 182
Quoted 7 lines
drivers/hv/dxgkrnl/dxgadapter.c +7
-0+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 ; + }
Just use list_del here.
Thanks,
Wei.
PATCH v3 11/30 drivers: hv: dxgkrnl: Operations using sync objects
In reply to Iouri TarassovImplement ioctls to submit operations with compute device sync objects:
- the LX_DXSIGNALSYNCHRONIZATIONOBJECT ioctl.
The ioctl is used to submit a signal to a sync object.
- the LX_DXWAITFORSYNCHRONIZATIONOBJECT ioctl.
The ioctl is used to submit a wait for a sync object
- the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU ioctl The ioctl is used to signal to a monitored fence sync object from a CPU thread.
- the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU ioctl. The ioctl is used to submit a signal to a monitored fence sync object..
- the LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU2 ioctl. The ioctl is used to submit a signal to a monitored fence sync object.
- the LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU ioctl. The ioctl is used to submit a wait for a monitored fence sync object.
Compute device synchronization objects are used to synchronize execution of DMA buffers between different execution contexts. Operations with sync objects include "signal" and "wait". A wait for a sync object is satisfied when the sync object is signaled.
A signal operation could be submitted to a compute device context or the sync object could be signaled by a CPU thread.
To improve performance, submitting operations to the host is done asynchronously when the host supports it.
--- drivers/hv/dxgkrnl/dxgadapter.c | 21 + drivers/hv/dxgkrnl/dxgkrnl.h | 62 +++ drivers/hv/dxgkrnl/dxgmodule.c | 97 +++++ drivers/hv/dxgkrnl/dxgvmbus.c | 213 ++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 48 +++ drivers/hv/dxgkrnl/ioctl.c | 693 ++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/misc.h | 1 + include/uapi/misc/d3dkmthk.h | 159 ++++++++ 8 files changed, 1294 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +21 -0
@@ -897,6 +897,12 @@ 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 ; }
@@ -924,6 +930,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 ;
@@ -933,6 +941,7 @@ void dxgsyncobject_destroy(struct dxgprocess *process, struct dxgsyncobject *syncobj) {int destroyed; +struct dxghosteventcpu *host_event;pr_debug ("%s 0x%p" , __func__, syncobj);
@@ -951,6 +960,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
@@ -990,5 +1009,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/dxgvmbus.h +48 -0
58 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
@@ -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
include/uapi/misc/d3dkmthk.h +159 -0
183 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 12/30 drivers: hv: dxgkrnl: Sharing of dxgresource objects
In reply to Iouri TarassovImplement creation of shared resources and ioctls for sharing dxgresource objects between processes in the virtual machine.
A dxgresource object is a collection of dxgallocation objects. The driver API allows addition/removal of allocations to a resource, but has limitations on addition/removal of allocations to a shared resource. When a resource is "sealed", addition/removal of allocations is not allowed.
Resources are shared using file descriptor (FD) handles. The name "NT handle" is used to be compatible with Windows implementation.
An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The given FD handle could be sent to another process using any Linux API.
To use a shared resource object in other ioctls the object needs to be opened using its FD handle. An resource object is opened by the LX_DXOPENRESOURCEFROMNTHANDLE ioctl. This ioctl returns a d3dkmthandle value, which can be used to reference the resource object.
The LX_DXQUERYRESOURCEINFOFROMNTHANDLE ioctl is used to query private driver data of a shared resource object. This private data needs to be used to actually open the object using the LX_DXOPENRESOURCEFROMNTHANDLE ioctl.
--- drivers/hv/dxgkrnl/dxgadapter.c | 81 ++++ drivers/hv/dxgkrnl/dxgkrnl.h | 77 ++++ drivers/hv/dxgkrnl/dxgmodule.c | 1 + drivers/hv/dxgkrnl/dxgvmbus.c | 127 ++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 30 ++ drivers/hv/dxgkrnl/ioctl.c | 786 ++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 96 ++++ 7 files changed, 1198 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +81 -0
@@ -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) {
@@ -493,6 +504,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 ));
@@ -535,6 +609,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);
@@ -550,6 +625,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
@@ -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/dxgvmbus.h +30 -0
@@ -172,6 +172,21 @@ struct dxgkvmb_command_signalguestevent {bool dereference_event; }; +/* +* The command returns struct d3dkmthandle of a shared object for the +* given pre-process object +*/ +struct dxgkvmb_command_createntsharedobject { +struct dxgkvmb_command_vm_to_host hdr; +struct d3dkmthandle object; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroyntsharedobject { +struct dxgkvmb_command_vm_to_host hdr; +struct d3dkmthandle shared_handle; +}; +/* Returns ntstatus */ struct dxgkvmb_command_setiospaceregion {struct dxgkvmb_command_vm_to_host hdr;
@@ -305,6 +320,21 @@ struct dxgkvmb_command_createallocation {/* u8 priv_drv_data[] for each alloc_info */ }; +struct dxgkvmb_command_openresource { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +bool nt_security_sharing; +struct d3dkmthandle global_share; +u32 allocation_count; +u32 total_priv_drv_data_size; +}; + +struct dxgkvmb_command_openresource_return { +struct d3dkmthandle resource; +struct ntstatus status; +/* struct d3dkmthandle allocation[allocation_count]; */ +}; +struct dxgkvmb_command_getstandardallocprivdata {struct dxgkvmb_command_vgpu_to_host hdr;enum d3dkmdt_standardallocationtype alloc_type;
drivers/hv/dxgkrnl/ioctl.c +786 -0
841 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +96 -0
108 lines not on this page · raw message
Signature · 1 line
2.35.1
Wei Liu
maintainerRe: [PATCH v3 12/30] drivers: hv: dxgkrnl: Sharing of dxgresource objects
On Tue, Mar 01, 2022 at 11:45:59AM -0800, Iouri Tarassov wrote:
[...]
Quoted 19 lines
drivers/hv/dxgkrnl/ioctl.c +18
-0+static int dxgsharedresource_seal (struct dxgsharedresource *shared_resource) +{ +int ret =0 ; +int i =0 ; +u8 *private_data; +u32 data_size; +struct dxgresource *resource; +struct dxgallocation *alloc; + +pr_debug ("Sealing resource: %p" , shared_resource); + +down_write (&shared_resource->adapter->shared_resource_list_lock); +if (shared_resource->sealed) { +pr_debug ("Resource already sealed" ); + goto cleanup; + } + shared_resource->sealed =1 ; +if (!list_empty (&shared_resource->resource_list_head)) {
[...]
Review
Quoted 2 lines
(quoted diff) +2
-0+ } +cleanup1:
Please just name it unlock ...
drivers/hv/dxgkrnl/ioctl.c dxgkp_enum_adapters(struct dxgprocess *process, · line 333
Quoted 3 lines
drivers/hv/dxgkrnl/ioctl.c +3
-0+mutex_unlock (&resource->resource_mutex); + } +cleanup:
... and rename this to done because you are not cleaning up anything.
drivers/hv/dxgkrnl/ioctl.c dxgkp_enum_adapters(struct dxgprocess *process, · line 337
Quoted 4 lines
drivers/hv/dxgkrnl/ioctl.c +4
-0+up_write (&shared_resource->adapter->shared_resource_list_lock); +return ret; +} +
Thanks,
Wei.
Wei Liu
maintainerRe: [PATCH v3 12/30] drivers: hv: dxgkrnl: Sharing of dxgresource objects
In reply to Iouri TarassovOn Tue, Mar 01, 2022 at 11:45:59AM -0800, Iouri Tarassov wrote:
[...]
drivers/hv/dxgkrnl/dxgadapter.c void dxgadapter_remove_process(struct dxgprocess_adapter *process_info) · line 175
Quoted 8 lines
drivers/hv/dxgkrnl/dxgadapter.c +8
-0+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 ; + }
Again, just list_del please. I will skip pointing out this in later patches.
Thanks,
Wei.
PATCH v3 13/30 drivers: hv: dxgkrnl: Sharing of sync objects
In reply to Iouri TarassovImplement creation of a shared sync objects and the ioctl for sharing dxgsyncobject objects between processes in the virtual machine.
Sync objects are shared using file descriptor (FD) handles. The name "NT handle" is used to be compatible with Windows implementation.
An FD handle is created by the LX_DXSHAREOBJECTS ioctl. The created FD handle could be sent to another process using any Linux API.
To use a shared sync object in other ioctls, the object needs to be opened using its FD handle. A sync object is opened by the LX_DXOPENSYNCOBJECTFROMNTHANDLE2 ioctl, which returns a d3dkmthandle value.
--- 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/dxgvmbus.h | 15 ++ drivers/hv/dxgkrnl/ioctl.c | 240 ++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 20 +++ 7 files changed, 485 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +83 -0
@@ -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) {
@@ -956,6 +976,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,
@@ -1090,6 +1167,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
@@ -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/dxgvmbus.h +15 -0
@@ -172,6 +172,21 @@ struct dxgkvmb_command_signalguestevent {bool dereference_event; }; +struct dxgkvmb_command_opensyncobject { +struct dxgkvmb_command_vm_to_host hdr; +struct d3dkmthandle device; +struct d3dkmthandle global_sync_object; +u32 engine_affinity; +struct d3dddi_synchronizationobject_flags flags; +}; + +struct dxgkvmb_command_opensyncobject_return { +struct d3dkmthandle sync_object; +struct ntstatus status; +u64 gpu_virtual_address; +u64 guest_cpu_physical_address; +}; +/* * The command returns struct d3dkmthandle of a shared object for the * given pre-process object
drivers/hv/dxgkrnl/ioctl.c +240 -0
312 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +20 -0
@@ -690,6 +690,26 @@ struct d3dddi_openallocationinfo2 {__u64 reserved[6 ]; }; +struct d3dkmt_opensyncobjectfromnthandle2 { +__u64 nt_handle; +struct d3dkmthandle device; +struct d3dddi_synchronizationobject_flags flags; +struct d3dkmthandle sync_object; +__u32 reserved1; +union { +struct { +#ifdef __KERNEL__ +void *fence_value_cpu_va; +#else +__u64 fence_value_cpu_va; +#endif +__u64 fence_value_gpu_va; +__u32 engine_affinity; + } monitored_fence; +__u64 reserved[8 ]; + }; +}; +struct d3dkmt_openresourcefromnthandle {struct d3dkmthandle device;__u32 reserved;
Signature · 1 line
2.35.1
PATCH v3 14/30 drivers: hv: dxgkrnl: Creation of hardware queues. Sync object operations to hw queue.
In reply to Iouri TarassovImplement ioctls for creation/destruction of the hardware queue objects:
- LX_DXCREATEHWQUEUE
- LX_DXDESTROYHWQUEUE
Implement ioctls to submit "signal" and "wait" operations for sync objects to hardware queues:
- LX_DXSUBMITSIGNALSYNCOBJECTSTOHWQUEUE,
- LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE
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 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.
--- 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/dxgvmbus.h | 20 ++ drivers/hv/dxgkrnl/ioctl.c | 321 ++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 73 ++++++++ 7 files changed, 702 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +96 -0
@@ -758,6 +758,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) {
@@ -769,6 +772,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); }
@@ -795,6 +802,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 ));
@@ -1177,3 +1216,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
@@ -36,6 +36,7 @@ struct dxgresource;struct dxgsharedresource ;struct dxgsyncobject ;struct dxgsharedsyncobject ; +struct dxghwqueue ;#include "misc.h" #include "hmgr.h"
@@ -532,8 +533,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.
@@ -758,6 +783,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
@@ -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/dxgvmbus.h +20 -0
@@ -523,4 +523,24 @@ struct dxgkvmb_command_waitforsyncobjectfromgpu { /* struct d3dkmthandle ObjectHandles[object_count] */ }; +/* Returns the same structure */ +struct dxgkvmb_command_createhwqueue { +struct dxgkvmb_command_vgpu_to_host hdr; +struct ntstatus status; +struct d3dkmthandle hwqueue; +struct d3dkmthandle hwqueue_progress_fence; +void *hwqueue_progress_fence_cpuva; +u64 hwqueue_progress_fence_gpuva; +struct d3dkmthandle context; +struct d3dddi_createhwqueueflags flags; +u32 priv_drv_data_size; +char priv_drv_data[1 ]; +}; + +/* The command returns ntstatus */ +struct dxgkvmb_command_destroyhwqueue { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle hwqueue; +}; +#endif /* _DXGVMBUS_H */
drivers/hv/dxgkrnl/ioctl.c +321 -0
347 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +73 -0
97 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 15/30 drivers: hv: dxgkrnl: Creation of paging queue objects.
In reply to Iouri TarassovImplement ioctls for creation/destruction of the paging queue objects:
- LX_DXCREATEPAGINGQUEUE,
- LX_DXDESTROYPAGINGQUEUE
Paging queue objects (dxgpagingqueue) contain operations, which handle residency of device accessible allocations. An allocation is resident, when the device has access to it. For example, the allocation resides in local device memory or device page tables point to system memory which is made non-pageable.
Each paging queue has an associated monitored fence sync object, which is used to detect when a paging operation is completed.
--- drivers/hv/dxgkrnl/dxgadapter.c | 89 +++++++++++++++ drivers/hv/dxgkrnl/dxgkrnl.h | 24 +++++ drivers/hv/dxgkrnl/dxgprocess.c | 4 + drivers/hv/dxgkrnl/dxgvmbus.c | 74 +++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 17 +++ drivers/hv/dxgkrnl/ioctl.c | 184 ++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 27 +++++ 7 files changed, 419 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +89 -0
@@ -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) {
@@ -711,6 +727,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) {
@@ -894,6 +930,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
@@ -89,6 +89,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.
@@ -112,6 +122,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.
@@ -503,6 +517,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);
@@ -742,6 +759,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
@@ -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/dxgvmbus.h +17 -0
@@ -462,6 +462,23 @@ struct dxgkvmb_command_destroycontext {struct d3dkmthandle context; }; +struct dxgkvmb_command_createpagingqueue { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_createpagingqueue args; +}; + +struct dxgkvmb_command_createpagingqueue_return { +struct d3dkmthandle paging_queue; +struct d3dkmthandle sync_object; +u64 fence_storage_physical_address; +u64 fence_storage_offset; +}; + +struct dxgkvmb_command_destroypagingqueue { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle paging_queue; +}; +struct dxgkvmb_command_createsyncobject {struct dxgkvmb_command_vgpu_to_host hdr;struct d3dkmt_createsynchronizationobject2 args;
drivers/hv/dxgkrnl/ioctl.c +184 -0
202 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +27 -0
@@ -207,6 +207,29 @@ struct d3dddi_createhwqueueflags { }; }; +enum d3dddi_pagingqueue_priority { + _D3DDDI_PAGINGQUEUE_PRIORITY_BELOW_NORMAL =-1 , + _D3DDDI_PAGINGQUEUE_PRIORITY_NORMAL =0 , + _D3DDDI_PAGINGQUEUE_PRIORITY_ABOVE_NORMAL =1 , +}; + +struct d3dkmt_createpagingqueue { +struct d3dkmthandle device; +enum d3dddi_pagingqueue_priority priority; +struct d3dkmthandle paging_queue; +struct d3dkmthandle sync_object; +#ifdef __KERNEL__ +void *fence_cpu_virtual_address; +#else +__u64 fence_cpu_virtual_address; +#endif +__u32 physical_adapter_index; +}; + +struct d3dddi_destroypagingqueue { +struct d3dkmthandle paging_queue; +}; +enum d3dkmdt_gdisurfacetype { _D3DKMDT_GDISURFACE_INVALID =0 , _D3DKMDT_GDISURFACE_TEXTURE =1 ,
@@ -886,6 +909,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x05, struct d3dkmt_destroycontext)#define LX_DXCREATEALLOCATION \ _IOWR(0x47, 0x06, struct d3dkmt_createallocation) +#define LX_DXCREATEPAGINGQUEUE \ + _IOWR(0x47, 0x07, struct d3dkmt_createpagingqueue)#define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo)#define LX_DXCREATESYNCHRONIZATIONOBJECT \
@@ -904,6 +929,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x18, struct d3dkmt_createhwqueue)#define LX_DXDESTROYHWQUEUE \ _IOWR(0x47, 0x1b, struct d3dkmt_destroyhwqueue) +#define LX_DXDESTROYPAGINGQUEUE \ + _IOWR(0x47, 0x1c, struct d3dddi_destroypagingqueue)#define LX_DXDESTROYDEVICE \ _IOWR(0x47, 0x19, struct d3dkmt_destroydevice)#define LX_DXDESTROYSYNCHRONIZATIONOBJECT \
Signature · 1 line
2.35.1
PATCH v3 16/30 drivers: hv: dxgkrnl: Submit execution commands to the compute device
In reply to Iouri TarassovImplements ioctls for submission of compute device buffers for execution:
- LX_DXSUBMITCOMMAND
The ioctl is used to submit a command buffer to the device, working in the "packet scheduling" mode.
- LX_DXSUBMITCOMMANDTOHWQUEUE
The ioctl is used to submit a command buffer to the device, working in the "hardware scheduling" mode.
To improve performance both ioctls use asynchronous VM bus messages to communicate with the host as these are high frequency operations.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 6 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 111 +++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 14 ++++ drivers/hv/dxgkrnl/ioctl.c | 129 ++++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 58 +++++++++++++++ 5 files changed, 318 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +6 -0
@@ -776,6 +776,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
@@ -818,6 +821,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/dxgvmbus.h +14 -0
@@ -314,6 +314,20 @@ struct dxgkvmb_command_flushdevice {enum dxgdevice_flushschedulerreason reason; }; +struct dxgkvmb_command_submitcommand { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_submitcommand args; +/* HistoryBufferHandles */ +/* PrivateDriverData */ +}; + +struct dxgkvmb_command_submitcommandtohwqueue { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_submitcommandtohwqueue args; +/* Written primaries */ +/* PrivateDriverData */ +}; +struct dxgkvmb_command_createallocation_allocinfo {u32 flags;u32 priv_drv_data_size;
drivers/hv/dxgkrnl/ioctl.c +129 -0
147 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +58 -0
82 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 17/30 drivers: hv: dxgkrnl: Share objects with the host
In reply to Iouri TarassovImplement the LX_DXSHAREOBJECTWITHHOST ioctl.
This ioctl is used to create a Windows NT handle on the host for the given shared object (resource or sync object). The NT handle is returned to the caller. The caller could share the NT handle with a host application, which needs to access the object. The host application can open the shared resource using the NT handle. This way the guest and the host have access to the same object.
Fix incorrect handling of error results from copy_from_user().
--- drivers/hv/dxgkrnl/dxgkrnl.h | 2 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 60 ++++++++++++++++++++++++++++--- drivers/hv/dxgkrnl/dxgvmbus.h | 18 ++++++++++ drivers/hv/dxgkrnl/ioctl.c | 68 ++++++++++++++++++++++++++++------- include/uapi/misc/d3dkmthk.h | 9 +++++ 5 files changed, 140 insertions(+), 17 deletions(-)
drivers/hv/dxgkrnl/dxgkrnl.h +2 -0
@@ -852,6 +852,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 +18 -0
@@ -574,4 +574,22 @@ struct dxgkvmb_command_destroyhwqueue { struct d3dkmthandle hwqueue; }; +struct dxgkvmb_command_shareobjectwithhost { +struct dxgkvmb_command_vm_to_host hdr; +struct d3dkmthandle device_handle; +struct d3dkmthandle object_handle; +u64 reserved; +}; + +struct dxgkvmb_command_shareobjectwithhost_return { +struct ntstatus status; +u32 alignment; +u64 vail_nt_handle; +}; + +int +dxgvmb_send_sync_msg (struct dxgvmbuschannel *channel, +void *command,u32 command_size,void *result, +u32 result_size); +#endif /* _DXGVMBUS_H */
drivers/hv/dxgkrnl/ioctl.c +56 -12
153 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +9 -0
@@ -948,6 +948,13 @@ struct d3dkmt_enumadapters3 {#endif }; +struct d3dkmt_shareobjectwithhost { +struct d3dkmthandle device_handle; +struct d3dkmthandle object_handle; +__u64 reserved; +__u64 object_vail_nt_handle; +}; +/* * Dxgkrnl Graphics Port Driver ioctl definitions *
@@ -1017,6 +1024,8 @@ struct d3dkmt_enumadapters3 { _IOWR(0x47, 0x41, struct d3dkmt_queryresourceinfofromnthandle)#define LX_DXOPENRESOURCEFROMNTHANDLE \ _IOWR(0x47, 0x42, struct d3dkmt_openresourcefromnthandle) +#define LX_DXSHAREOBJECTWITHHOST \ + _IOWR(0x47, 0x44, struct d3dkmt_shareobjectwithhost)#define LX_IO_MAX 0x45
Signature · 1 line
2.35.1
PATCH v3 18/30 drivers: hv: dxgkrnl: Query the dxgdevice state
In reply to Iouri TarassovImplement the ioctl to query the dxgdevice state - LX_DXGETDEVICESTATE. The IOCTL is used to query the state of the given dxgdevice object (active, error, etc.).
A call to the dxgdevice execution state could be high frequency. The following method is used to avoid sending a synchronous VM bus message to the host for every call:
- When a dxgdevice is created, a pointer to dxgglobal->device_state_counter is sent to the host
- Every time the device state on the host is changed, the host will send an asynchronous message to the guest (DXGK_VMBCOMMAND_SETGUESTDATA) and the guest will increment the device_state_counter value.
- the dxgdevice object has execution_state_counter member, which is equal to dxgglobal->device_state_counter value at the time when LX_DXGETDEVICESTATE was last processed..
- if execution_state_counter is different from device_state_counter, the dxgk_vmbcommand_getdevicestate VM bus message is sent to the host. Otherwise, the cached value is returned to the caller.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 11 ++++ drivers/hv/dxgkrnl/dxgvmbus.c | 66 ++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 26 +++++++++ drivers/hv/dxgkrnl/ioctl.c | 66 ++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 101 ++++++++++++++++++++++++++++++---- 5 files changed, 260 insertions(+), 10 deletions(-)
drivers/hv/dxgkrnl/dxgkrnl.h +11 -0
@@ -253,12 +253,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;
@@ -499,6 +505,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; };
@@ -829,6 +836,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/dxgvmbus.h +26 -0
@@ -172,6 +172,22 @@ struct dxgkvmb_command_signalguestevent {bool dereference_event; }; +enum set_guestdata_type { +SETGUESTDATA_DATATYPE_DWORD =0 , +SETGUESTDATA_DATATYPE_UINT64 =1 +}; + +struct dxgkvmb_command_setguestdata { +struct dxgkvmb_command_host_to_vm hdr; +void *guest_pointer; +union { +u64 data64; +u32 data32; + }; +u32 dereference :1 ; +u32 data_type :4 ; +}; +struct dxgkvmb_command_opensyncobject {struct dxgkvmb_command_vm_to_host hdr;struct d3dkmthandle device;
@@ -574,6 +590,16 @@ struct dxgkvmb_command_destroyhwqueue {struct d3dkmthandle hwqueue; }; +struct dxgkvmb_command_getdevicestate { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_getdevicestate args; +}; + +struct dxgkvmb_command_getdevicestate_return { +struct d3dkmt_getdevicestate args; +struct ntstatus status; +}; +struct dxgkvmb_command_shareobjectwithhost {struct dxgkvmb_command_vm_to_host hdr;struct d3dkmthandle device_handle;
drivers/hv/dxgkrnl/ioctl.c +66 -0
78 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +91 -10
119 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 19/30 drivers: hv: dxgkrnl: Map(unmap) CPU address to device allocation
In reply to Iouri TarassovImplement ioctls to map/unmap CPU virtual addresses to compute device allocations - LX_DXLOCK2 and LX_DXUNLOCK2.
The LX_DXLOCK2 ioctl maps a CPU virtual address to a compute device allocation. The allocation could be located in system memory or local device memory on the host. When the device allocation is created from the guest system memory (existing sysmem allocation), the allocation CPU address is known and is returned to the caller. For other CPU visible allocations the code flow is the following:
1. A VM bus message is sent to the host to map the allocation
2. The host allocates a portion of the guest IO space and maps it to the allocation backing store. The IO space address of the allocation is returned back to the guest.
3. The guest allocates a CPU virtual address and maps it to the IO space (see the dxg_map_iospace function).
4. The CPU VA is returned back to the caller cpu_address_mapped and cpu_address_refcount are used to track how many times an allocation was mapped.
The LX_DXUNLOCK2 ioctl unmaps a CPU virtual address from a compute device allocation.
--- drivers/hv/dxgkrnl/dxgadapter.c | 11 +++ drivers/hv/dxgkrnl/dxgkrnl.h | 14 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 107 +++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 19 ++++ drivers/hv/dxgkrnl/ioctl.c | 161 ++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 30 ++++++ 6 files changed, 342 insertions(+)
drivers/hv/dxgkrnl/dxgadapter.c +11 -0
@@ -886,6 +886,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)
@@ -927,6 +936,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
@@ -695,6 +695,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;
@@ -702,6 +704,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
@@ -817,6 +824,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/dxgvmbus.h +19 -0
@@ -570,6 +570,25 @@ struct dxgkvmb_command_waitforsyncobjectfromgpu {/* struct d3dkmthandle ObjectHandles[object_count] */ }; +struct dxgkvmb_command_lock2 { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_lock2 args; +bool use_legacy_lock; +u32 flags; +u32 priv_drv_data; +}; + +struct dxgkvmb_command_lock2_return { +struct ntstatus status; +void *cpu_visible_buffer_offset; +}; + +struct dxgkvmb_command_unlock2 { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_unlock2 args; +bool use_legacy_unlock; +}; +/* Returns the same structure */ struct dxgkvmb_command_createhwqueue {struct dxgkvmb_command_vgpu_to_host hdr;
drivers/hv/dxgkrnl/ioctl.c +161 -0
179 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +30 -0
@@ -664,6 +664,32 @@ struct d3dkmt_submitcommandtohwqueue {#endif }; +struct d3dddicb_lock2flags { +union { +struct { +__u32 reserved:32 ; + }; +__u32 value; + }; +}; + +struct d3dkmt_lock2 { +struct d3dkmthandle device; +struct d3dkmthandle allocation; +struct d3dddicb_lock2flags flags; +__u32 reserved; +#ifdef __KERNEL__ +void *data; +#else +__u64 data; +#endif +}; + +struct d3dkmt_unlock2 { +struct d3dkmthandle device; +struct d3dkmthandle allocation; +}; +enum d3dkmt_standardallocationtype { _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP =1 , _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER =2 ,
@@ -1079,6 +1105,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x19, struct d3dkmt_destroydevice)#define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) +#define LX_DXLOCK2 \ + _IOWR(0x47, 0x25, struct d3dkmt_lock2)#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x31, struct d3dkmt_signalsynchronizationobjectfromcpu)#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU \
@@ -1091,6 +1119,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x35, struct d3dkmt_submitsignalsyncobjectstohwqueue)#define LX_DXSUBMITWAITFORSYNCOBJECTSTOHWQUEUE \ _IOWR(0x47, 0x36, struct d3dkmt_submitwaitforsyncobjectstohwqueue) +#define LX_DXUNLOCK2 \ + _IOWR(0x47, 0x37, struct d3dkmt_unlock2)#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x3a, struct d3dkmt_waitforsynchronizationobjectfromcpu)#define LX_DXWAITFORSYNCHRONIZATIONOBJECTFROMGPU \
Signature · 1 line
2.35.1
PATCH v3 20/30 drivers: hv: dxgkrnl: Manage device allocation properties
In reply to Iouri TarassovImplement ioctls to manage properties of a compute device allocation:
- LX_DXUPDATEALLOCPROPERTY,
- LX_DXSETALLOCATIONPRIORITY,
- LX_DXGETALLOCATIONPRIORITY,
- LX_DXQUERYALLOCATIONRESIDENCY.
- LX_DXCHANGEVIDEOMEMORYRESERVATION,
The LX_DXUPDATEALLOCPROPERTY ioctl requests the host to update various properties of a compute devoce allocation.
The LX_DXSETALLOCATIONPRIORITY and LX_DXGETALLOCATIONPRIORITY ioctls are used to set/get allocation priority, which defines the importance of the allocation to be in the local device memory.
The LX_DXQUERYALLOCATIONRESIDENCY ioctl queries if the allocation is located in the compute device accessible memory.
The LX_DXCHANGEVIDEOMEMORYRESERVATION ioctl changes compute device memory reservation of an allocation.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 21 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 300 ++++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 50 ++++++ drivers/hv/dxgkrnl/ioctl.c | 212 ++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 127 ++++++++++++++ 5 files changed, 710 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +21 -0
@@ -831,6 +831,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,
@@ -850,6 +867,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/dxgvmbus.h +50 -0
68 lines not on this page · raw message
drivers/hv/dxgkrnl/ioctl.c +212 -0
240 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +127 -0
167 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 21/30 drivers: hv: dxgkrnl: Flush heap transitions
In reply to Iouri TarassovImplement the ioctl to flush heap transitions
(LX_DXFLUSHHEAPTRANSITIONS).
The ioctl is used to ensure that the video memory manager on the host flushes all internal operations.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 3 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 23 ++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 5 ++++ drivers/hv/dxgkrnl/ioctl.c | 49 +++++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 6 +++++ 5 files changed, 86 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +3 -0
@@ -862,6 +862,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
drivers/hv/dxgkrnl/dxgvmbus.c +23 -0
@@ -1812,6 +1812,29 @@ int dxgvmb_send_destroy_allocation(struct dxgprocess *process,return ret; } +int dxgvmb_send_flush_heap_transitions (struct dxgprocess *process, +struct dxgadapter *adapter, +struct d3dkmt_flushheaptransitions *args) +{ +struct dxgkvmb_command_flushheaptransitions *command; +int ret; +struct dxgvmbusmsg msg = {.hdr =NULL }; + + ret =init_message (&msg, adapter, process,sizeof (*command)); +if (ret) + goto cleanup; + command = (void *)msg.msg; +command_vgpu_to_host_init2 (&command->hdr, +DXGK_VMBCOMMAND_FLUSHHEAPTRANSITIONS , + process->host_handle); + ret =dxgvmb_send_sync_msg_ntstatus (msg.channel, msg.hdr, msg.size); +cleanup: +free_message (&msg, process); +if (ret) +pr_debug ("err: %s %d" , __func__, ret); +return ret; +} +int dxgvmb_send_query_alloc_residency (struct dxgprocess *process,struct dxgadapter *adapter, struct d3dkmt_queryallocationresidency
drivers/hv/dxgkrnl/dxgvmbus.h +5 -0
@@ -367,6 +367,11 @@ struct dxgkvmb_command_submitcommandtohwqueue {/* PrivateDriverData */ }; +/* Returns ntstatus */ +struct dxgkvmb_command_flushheaptransitions { +struct dxgkvmb_command_vgpu_to_host hdr; +}; +struct dxgkvmb_command_createallocation_allocinfo {u32 flags;u32 priv_drv_data_size;
drivers/hv/dxgkrnl/ioctl.c +49 -0
61 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +6 -0
@@ -932,6 +932,10 @@ struct d3dkmt_queryadapterinfo {__u32 private_data_size; }; +struct d3dkmt_flushheaptransitions { +struct d3dkmthandle adapter; +}; +struct d3dddi_openallocationinfo2 {struct d3dkmthandle allocation;#ifdef __KERNEL__
@@ -1224,6 +1228,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x19, struct d3dkmt_destroydevice)#define LX_DXDESTROYSYNCHRONIZATIONOBJECT \ _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject) +#define LX_DXFLUSHHEAPTRANSITIONS \ + _IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions)#define LX_DXLOCK2 \ _IOWR(0x47, 0x25, struct d3dkmt_lock2)#define LX_DXQUERYALLOCATIONRESIDENCY \
Signature · 1 line
2.35.1
PATCH v3 22/30 drivers: hv: dxgkrnl: Query video memory information
In reply to Iouri TarassovImplement the ioctl to query video memory information from the host (LX_DXQUERYVIDEOMEMORYINFO).
--- drivers/hv/dxgkrnl/dxgkrnl.h | 5 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 64 +++++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 14 ++++++++ drivers/hv/dxgkrnl/ioctl.c | 50 +++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 13 +++++++ 5 files changed, 146 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +5 -0
@@ -874,6 +874,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 +64 -0
70 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.h +14 -0
@@ -664,6 +664,20 @@ struct dxgkvmb_command_queryallocationresidency_return {/* d3dkmt_allocationresidencystatus[NumAllocations] */ }; +struct dxgkvmb_command_queryvideomemoryinfo { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle adapter; +enum d3dkmt_memory_segment_group memory_segment_group; +u32 physical_adapter_index; +}; + +struct dxgkvmb_command_queryvideomemoryinfo_return { +u64 budget; +u64 current_usage; +u64 current_reservation; +u64 available_for_reservation; +}; +struct dxgkvmb_command_getdevicestate {struct dxgkvmb_command_vgpu_to_host hdr;struct d3dkmt_getdevicestate args;
drivers/hv/dxgkrnl/ioctl.c +50 -0
62 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +13 -0
@@ -893,6 +893,17 @@ enum d3dkmt_memory_segment_group { _D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL =1 }; +struct d3dkmt_queryvideomemoryinfo { +__u64 process; +struct d3dkmthandle adapter; +enum d3dkmt_memory_segment_group memory_segment_group; +__u64 budget; +__u64 current_usage; +__u64 current_reservation; +__u64 available_for_reservation; +__u32 physical_adapter_index; +}; + struct d3dkmt_adaptertype { union { struct {
@@ -1200,6 +1211,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x07, struct d3dkmt_createpagingqueue)#define LX_DXQUERYADAPTERINFO \ _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) +#define LX_DXQUERYVIDEOMEMORYINFO \ + _IOWR(0x47, 0x0a, struct d3dkmt_queryvideomemoryinfo)#define LX_DXGETDEVICESTATE \ _IOWR(0x47, 0x0e, struct d3dkmt_getdevicestate)#define LX_DXSUBMITCOMMAND \
Signature · 1 line
2.35.1
PATCH v3 23/30 drivers: hv: dxgkrnl: The escape ioctl
In reply to Iouri TarassovImplement the escape ioctl (LX_DXESCAPE).
This ioctl is used to send/receive private data between user mode compute device driver (guest) and kernel mode compute device driver (host). It allows the user mode driver to extend the virtual compute device API.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 3 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 65 +++++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 12 +++++++ drivers/hv/dxgkrnl/ioctl.c | 42 ++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 41 ++++++++++++++++++++++ 5 files changed, 163 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +3 -0
@@ -874,6 +874,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,
drivers/hv/dxgkrnl/dxgvmbus.c +65 -0
74 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.h +12 -0
@@ -664,6 +664,18 @@ struct dxgkvmb_command_queryallocationresidency_return {/* d3dkmt_allocationresidencystatus[NumAllocations] */ }; +/* Returns only private data */ +struct dxgkvmb_command_escape { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle adapter; +struct d3dkmthandle device; +enum d3dkmt_escapetype type; +struct d3dddi_escapeflags flags; +u32 priv_drv_data_size; +struct d3dkmthandle context; +u8 priv_drv_data[1 ]; +}; +struct dxgkvmb_command_queryvideomemoryinfo {struct dxgkvmb_command_vgpu_to_host hdr;struct d3dkmthandle adapter;
drivers/hv/dxgkrnl/ioctl.c +42 -0
54 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +41 -0
53 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 24/30 drivers: hv: dxgkrnl: Ioctl to put device to error state
In reply to Iouri TarassovImplement the ioctl to put the virtual compute device to the error state (LX_DXMARKDEVICEASERROR).
This ioctl is used by the user mode driver when it detects an unrecoverable error condition.
When a compute device is put to the error state, all subsequent ioctl calls to the device will fail.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 3 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 25 ++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 5 +++++ drivers/hv/dxgkrnl/ioctl.c | 39 +++++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 12 +++++++++++ 5 files changed, 84 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +3 -0
@@ -836,6 +836,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);
drivers/hv/dxgkrnl/dxgvmbus.c +25 -0
@@ -2708,6 +2708,31 @@ int dxgvmb_send_update_alloc_property(struct dxgprocess *process,return ret; } +int dxgvmb_send_mark_device_as_error (struct dxgprocess *process, +struct dxgadapter *adapter, +struct d3dkmt_markdeviceaserror *args) +{ +struct dxgkvmb_command_markdeviceaserror *command; +int ret; +struct dxgvmbusmsg msg = {.hdr =NULL }; + + ret =init_message (&msg, adapter, process,sizeof (*command)); +if (ret) + goto cleanup; + command = (void *)msg.msg; + +command_vgpu_to_host_init2 (&command->hdr, +DXGK_VMBCOMMAND_MARKDEVICEASERROR , + process->host_handle); + command->args = *args; + ret =dxgvmb_send_sync_msg_ntstatus (msg.channel, msg.hdr, msg.size); +cleanup: +free_message (&msg, process); +if (ret) +pr_debug ("err: %s %d" , __func__, ret); +return ret; +} +int dxgvmb_send_set_allocation_priority (struct dxgprocess *process,struct dxgadapter *adapter,struct d3dkmt_setallocationpriority *args)
drivers/hv/dxgkrnl/dxgvmbus.h +5 -0
@@ -627,6 +627,11 @@ struct dxgkvmb_command_updateallocationproperty_return {struct ntstatus status; }; +struct dxgkvmb_command_markdeviceaserror { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_markdeviceaserror args; +}; +/* Returns ntstatus */ struct dxgkvmb_command_changevideomemoryreservation {struct dxgkvmb_command_vgpu_to_host hdr;
drivers/hv/dxgkrnl/ioctl.c +39 -0
@@ -3380,6 +3380,43 @@ dxgk_update_alloc_property(struct dxgprocess *process, void *__user inargs)return ret; } +static int +dxgk_mark_device_as_error (struct dxgprocess *process,void *__user inargs) +{ +struct d3dkmt_markdeviceaserror args; +struct dxgadapter *adapter =NULL ; +struct dxgdevice *device =NULL ; +int ret; + +pr_debug ("ioctl: %s" , __func__); + ret =copy_from_user (&args, inargs,sizeof (args)); +if (ret) { +pr_err ("%s failed to copy input args" , __func__); + ret = -EINVAL ; + goto cleanup; + } + device =dxgprocess_device_by_handle (process, args.device); +if (device ==NULL ) { + ret = -EINVAL ; + goto cleanup; + } + adapter = device->adapter; + ret =dxgadapter_acquire_lock_shared (adapter); +if (ret <0 ) { + adapter =NULL ; + goto cleanup; + } + device->execution_state = _D3DKMT_DEVICEEXECUTION_RESET; + ret =dxgvmb_send_mark_device_as_error (process, adapter, &args); +cleanup: +if (adapter) +dxgadapter_release_lock_shared (adapter); +if (device) +kref_put (&device->device_kref, dxgdevice_release); +pr_debug ("ioctl:%s %s %d" ,errorstr (ret), __func__, ret); +return ret; +} +static int dxgk_query_alloc_residency (struct dxgprocess *process,void *__user inargs) {
@@ -4515,6 +4552,8 @@ void init_ioctls(void) LX_DXFLUSHHEAPTRANSITIONS);SET_IOCTL (/*0x25 */ dxgk_lock2,LX_DXLOCK2 ); +SET_IOCTL (/*0x26 */ dxgk_mark_device_as_error, +LX_DXMARKDEVICEASERROR );SET_IOCTL (/*0x2a */ dxgk_query_alloc_residency,LX_DXQUERYALLOCATIONRESIDENCY ); SET_IOCTL(/*0x2e */ dxgk_set_allocation_priority,
include/uapi/misc/d3dkmthk.h +12 -0
@@ -786,6 +786,16 @@ struct d3dkmt_unlock2 {struct d3dkmthandle allocation; }; +enum d3dkmt_device_error_reason { + _D3DKMT_DEVICE_ERROR_REASON_GENERIC =0x80000000 , + _D3DKMT_DEVICE_ERROR_REASON_DRIVER_ERROR =0x80000006 , +}; + +struct d3dkmt_markdeviceaserror { +struct d3dkmthandle device; +enum d3dkmt_device_error_reason reason; +}; +enum d3dkmt_standardallocationtype { _D3DKMT_STANDARDALLOCATIONTYPE_EXISTINGHEAP =1 , _D3DKMT_STANDARDALLOCATIONTYPE_CROSSADAPTER =2 ,
@@ -1286,6 +1296,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions)#define LX_DXLOCK2 \ _IOWR(0x47, 0x25, struct d3dkmt_lock2) +#define LX_DXMARKDEVICEASERROR \ + _IOWR(0x47, 0x26, struct d3dkmt_markdeviceaserror)#define LX_DXQUERYALLOCATIONRESIDENCY \ _IOWR(0x47, 0x2a, struct d3dkmt_queryallocationresidency)#define LX_DXSETALLOCATIONPRIORITY \
Signature · 1 line
2.35.1
PATCH v3 25/30 drivers: hv: dxgkrnl: Ioctls to query statistics and clock calibration
In reply to Iouri TarassovImplement ioctls to query statistics from the VGPU device (LX_DXQUERYSTATISTICS) and to query clock calibration (LX_DXQUERYCLOCKCALIBRATION).
The LX_DXQUERYSTATISTICS ioctl is used to query various statistics from the compute device on the host.
The LX_DXQUERYCLOCKCALIBRATION ioctl queries the compute device clock and is used for performance monitoring.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 8 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 77 +++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 21 +++++++ drivers/hv/dxgkrnl/ioctl.c | 112 ++++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 62 +++++++++++++++++++ 5 files changed, 280 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +8 -0
@@ -865,6 +865,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);
@@ -909,6 +914,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 +77 -0
86 lines not on this page · raw message
drivers/hv/dxgkrnl/dxgvmbus.h +21 -0
@@ -372,6 +372,16 @@ struct dxgkvmb_command_flushheaptransitions {struct dxgkvmb_command_vgpu_to_host hdr; }; +struct dxgkvmb_command_queryclockcalibration { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_queryclockcalibration args; +}; + +struct dxgkvmb_command_queryclockcalibration_return { +struct ntstatus status; +struct dxgk_gpuclockdata clock_data; +}; +struct dxgkvmb_command_createallocation_allocinfo {u32 flags;u32 priv_drv_data_size;
@@ -408,6 +418,17 @@ struct dxgkvmb_command_openresource_return {/* struct d3dkmthandle allocation[allocation_count]; */ }; +struct dxgkvmb_command_querystatistics { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_querystatistics args; +}; + +struct dxgkvmb_command_querystatistics_return { +struct ntstatus status; +u32 reserved; +struct d3dkmt_querystatistics_result result; +}; +struct dxgkvmb_command_getstandardallocprivdata {struct dxgkvmb_command_vgpu_to_host hdr;enum d3dkmdt_standardallocationtype alloc_type;
drivers/hv/dxgkrnl/ioctl.c +112 -0
136 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +62 -0
86 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 26/30 drivers: hv: dxgkrnl: Offer and reclaim allocations
In reply to Iouri TarassovImplement ioctls to offer and reclaim compute device allocations:
- LX_DXOFFERALLOCATIONS,
- LX_DXRECLAIMALLOCATIONS2
When a user mode driver (UMD) does not need to access an allocation, it can "offer" it by issuing the LX_DXOFFERALLOCATIONS ioctl. This means that the allocation is not in use and its local device memory could be evicted. The freed space could be given to another allocation. When the allocation is again needed, the UMD can attempt to"reclaim" the allocation by issuing the LX_DXRECLAIMALLOCATIONS2 ioctl. If the allocation is still not evicted, the reclaim operation succeeds and no other action is required. If the reclaim operation fails, the caller must restore the content of the allocation before it can be used by the device.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 8 +++ drivers/hv/dxgkrnl/dxgvmbus.c | 122 ++++++++++++++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 27 ++++++++ drivers/hv/dxgkrnl/ioctl.c | 119 +++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 67 +++++++++++++++++++ 5 files changed, 343 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +8 -0
@@ -845,6 +845,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/dxgvmbus.h +27 -0
@@ -653,6 +653,33 @@ struct dxgkvmb_command_markdeviceaserror {struct d3dkmt_markdeviceaserror args; }; +/* Returns ntstatus */ +struct dxgkvmb_command_offerallocations { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +u32 allocation_count; +enum d3dkmt_offer_priority priority; +struct d3dkmt_offer_flags flags; +bool resources; +struct d3dkmthandle allocations[1 ]; +}; + +struct dxgkvmb_command_reclaimallocations { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +struct d3dkmthandle paging_queue; +u32 allocation_count; +bool resources; +bool write_results; +struct d3dkmthandle allocations[1 ]; +}; + +struct dxgkvmb_command_reclaimallocations_return { +u64 paging_fence_value; +struct ntstatus status; +enum d3dddi_reclaim_result discarded[1 ]; +}; +/* Returns ntstatus */ struct dxgkvmb_command_changevideomemoryreservation {struct dxgkvmb_command_vgpu_to_host hdr;
drivers/hv/dxgkrnl/ioctl.c +119 -0
133 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +67 -0
87 lines not on this page · raw message
Signature · 1 line
2.35.1
Wei Liu
maintainerRe: [PATCH v3 26/30] drivers: hv: dxgkrnl: Offer and reclaim allocations
Quoted 5 lines · Iouri Tarassov
Implement ioctls to offer and reclaim compute device allocations:
-LX_DXOFFERALLOCATIONS,
-LX_DXRECLAIMALLOCATIONS2When a user mode driver (UMD) does not need to access an allocation,
What is a "user mode driver" in this context? Is that something that runs inside the guest?
Quoted 11 lines
it can "offer" it by issuing the
LX_DXOFFERALLOCATIONSioctl. This means that the allocation is not in use and its local device memory could be evicted. The freed space could be given to another allocation. When the allocation is again needed, the UMD can attempt to"reclaim" the allocation by issuing theLX_DXRECLAIMALLOCATIONS2ioctl. If the allocation is still not evicted, the reclaim operation succeeds and no other action is required. If the reclaim operation fails, the caller must restore the content of the allocation before it can be used by the device.Signed-off-by Iouri Tarassov <[email protected]>
Re: [PATCH v3 26/30] drivers: hv: dxgkrnl: Offer and reclaim allocations
Quoted 9 lines · Wei Liu
Quoted 5 lines · Iouri Tarassov
Implement ioctls to offer and reclaim compute device allocations:
-LX_DXOFFERALLOCATIONS,
-LX_DXRECLAIMALLOCATIONS2When a user mode driver (UMD) does not need to access an allocation,
What is a "user mode driver" in this context? Is that something that runs inside the guest?
Hi Wei,
The user mode driver runs inside the guest. This driver is written by hardware vendors.
For example, the NVIDIA's Cuda runtime is considered a user mode driver. The driver
provides a specific API to applications (like the Cuda API).
The cover letter explains the design of the virtual compute device paravirtualization
model and describes all components, which are involved. I feel that I do not need to
include explanation to every patch.
Thanks
Iouri
Wei Liu
maintainerRe: [PATCH v3 26/30] drivers: hv: dxgkrnl: Offer and reclaim allocations
Quoted 20 lines · Iouri Tarassov
Quoted 9 lines · Wei Liu
Quoted 5 lines · Iouri Tarassov
Implement ioctls to offer and reclaim compute device allocations:
-LX_DXOFFERALLOCATIONS,
-LX_DXRECLAIMALLOCATIONS2When a user mode driver (UMD) does not need to access an allocation,
What is a "user mode driver" in this context? Is that something that runs inside the guest?
Hi Wei,
The user mode driver runs inside the guest. This driver is written by hardware vendors.
For example, the NVIDIA's Cuda runtime is considered a user mode driver. The driver
provides a specific API to applications (like the Cuda API).
Quoted 5 lines
The cover letter explains the design of the virtual compute device paravirtualization
model and describes all components, which are involved. I feel that I do not need to
include explanation to every patch.
It's fine. I was just asking a question -- I didn't have all the terms in my head by the time I got to this patch. There is no need to add the explanation to every patch.
Thanks,
Wei.
Quoted 4 lines
Thanks
Iouri
PATCH v3 27/30 drivers: hv: dxgkrnl: Ioctls to manage scheduling priority
In reply to Iouri TarassovImplement iocts to manage compute device scheduling priority:
- LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY
- LX_DXGETCONTEXTSCHEDULINGPRIORITY
- LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY
- LX_DXSETCONTEXTSCHEDULINGPRIORITY
Each compute device execution context has an assigned scheduling priority. It is used by the compute device scheduler on the host to pick contexts for execution. There is a global priority and a priority within a process.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 9 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 63 +++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 19 ++++ drivers/hv/dxgkrnl/ioctl.c | 173 ++++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 28 ++++++ 5 files changed, 292 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +9 -0
@@ -845,6 +845,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/dxgvmbus.h +19 -0
@@ -331,6 +331,25 @@ struct dxgkvmb_command_getallocationpriority_return {/* u32 priorities[allocation_count or 1]; */ }; +/* Returns ntstatus */ +struct dxgkvmb_command_setcontextschedulingpriority2 { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle context; +int priority; +bool in_process; +}; + +struct dxgkvmb_command_getcontextschedulingpriority { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle context; +bool in_process; +}; + +struct dxgkvmb_command_getcontextschedulingpriority_return { +struct ntstatus status; +int priority; +}; +struct dxgkvmb_command_createdevice {struct dxgkvmb_command_vgpu_to_host hdr;struct d3dkmt_createdeviceflags flags;
drivers/hv/dxgkrnl/ioctl.c +173 -0
191 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +28 -0
@@ -704,6 +704,26 @@ struct d3dkmt_submitcommandtohwqueue {#endif }; +struct d3dkmt_setcontextschedulingpriority { +struct d3dkmthandle context; +int priority; +}; + +struct d3dkmt_setcontextinprocessschedulingpriority { +struct d3dkmthandle context; +int priority; +}; + +struct d3dkmt_getcontextschedulingpriority { +struct d3dkmthandle context; +int priority; +}; + +struct d3dkmt_getcontextinprocessschedulingpriority { +struct d3dkmthandle context; +int priority; +}; +struct d3dkmt_setallocationpriority {struct d3dkmthandle device;struct d3dkmthandle resource;
@@ -1415,6 +1435,10 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x1d, struct d3dkmt_destroysynchronizationobject)#define LX_DXFLUSHHEAPTRANSITIONS \ _IOWR(0x47, 0x1f, struct d3dkmt_flushheaptransitions) +#define LX_DXGETCONTEXTINPROCESSSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x21, struct d3dkmt_getcontextinprocessschedulingpriority) +#define LX_DXGETCONTEXTSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x22, struct d3dkmt_getcontextschedulingpriority)#define LX_DXLOCK2 \ _IOWR(0x47, 0x25, struct d3dkmt_lock2)#define LX_DXMARKDEVICEASERROR \
@@ -1427,6 +1451,10 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x2c, struct d3dkmt_reclaimallocations2)#define LX_DXSETALLOCATIONPRIORITY \ _IOWR(0x47, 0x2e, struct d3dkmt_setallocationpriority) +#define LX_DXSETCONTEXTINPROCESSSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x2f, struct d3dkmt_setcontextinprocessschedulingpriority) +#define LX_DXSETCONTEXTSCHEDULINGPRIORITY \ + _IOWR(0x47, 0x30, struct d3dkmt_setcontextschedulingpriority)#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMCPU \ _IOWR(0x47, 0x31, struct d3dkmt_signalsynchronizationobjectfromcpu)#define LX_DXSIGNALSYNCHRONIZATIONOBJECTFROMGPU \
Signature · 1 line
2.35.1
PATCH v3 28/30 drivers: hv: dxgkrnl: Manage residency of allocations
In reply to Iouri TarassovImplement ioctls to manage residency of compute device allocations:
- LX_DXMAKERESIDENT,
- LX_DXEVICT.
An allocation is "resident" when the compute devoce is setup to access it. It means that the allocation is in the local device memory or in non-pageable system memory.
The current design does not support on demand compute device page faulting. An allocation must be resident before the compute device is allowed to access it.
The LX_DXMAKERESIDENT ioctl instructs the video memory manager to make the given allocations resident. The operation is submitted to a paging queue (dxgpagingqueue). When the ioctl returns a "pending" status, a monitored fence sync object can be used to synchronize with the completion of the operation.
The LX_DXEVICT ioctl istructs the video memory manager to evict the given allocations from device accessible memory.
--- drivers/hv/dxgkrnl/dxgkrnl.h | 4 + drivers/hv/dxgkrnl/dxgvmbus.c | 98 +++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 27 +++++++ drivers/hv/dxgkrnl/ioctl.c | 144 ++++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 54 +++++++++++++ 5 files changed, 327 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +4 -0
@@ -790,6 +790,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/dxgvmbus.h +27 -0
@@ -372,6 +372,33 @@ struct dxgkvmb_command_flushdevice {enum dxgdevice_flushschedulerreason reason; }; +struct dxgkvmb_command_makeresident { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +struct d3dkmthandle paging_queue; +struct d3dddi_makeresident_flags flags; +u32 alloc_count; +struct d3dkmthandle allocations[1 ]; +}; + +struct dxgkvmb_command_makeresident_return { +u64 paging_fence_value; +u64 num_bytes_to_trim; +struct ntstatus status; +}; + +struct dxgkvmb_command_evict { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +struct d3dddi_evict_flags flags; +u32 alloc_count; +struct d3dkmthandle allocations[1 ]; +}; + +struct dxgkvmb_command_evict_return { +u64 num_bytes_to_trim; +}; +struct dxgkvmb_command_submitcommand {struct dxgkvmb_command_vgpu_to_host hdr;struct d3dkmt_submitcommand args;
drivers/hv/dxgkrnl/ioctl.c +144 -0
162 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +54 -0
72 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 29/30 drivers: hv: dxgkrnl: Manage compute device virtual addresses
In reply to Iouri TarassovImplement ioctls to manage compute device virtual addresses (VA):
- LX_DXRESERVEGPUVIRTUALADDRESS,
- LX_DXFREEGPUVIRTUALADDRESS,
- LX_DXMAPGPUVIRTUALADDRESS,
- LX_DXUPDATEGPUVIRTUALADDRESS.
Compute devices access memory by using virtual addressses. Each process has a dedicated VA space. The video memory manager on the host is responsible with updating device page tables before submitting a DMA buffer for execution.
The LX_DXRESERVEGPUVIRTUALADDRESS ioctl reserves a portion of the process compute device VA space.
The LX_DXMAPGPUVIRTUALADDRESS ioctl reserves a portion of the process compute device VA space and maps it to the given compute device allocation.
The LX_DXFREEGPUVIRTUALADDRESS frees the previously reserved portion of the compute device VA space.
The LX_DXUPDATEGPUVIRTUALADDRESS ioctl adds operations to modify the compute device VA space to a compute device execution context. It allows the operations to be queued and synchronized with execution of other compute device DMA buffers..
--- drivers/hv/dxgkrnl/dxgkrnl.h | 10 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 150 ++++++++++++++++++++++ drivers/hv/dxgkrnl/dxgvmbus.h | 38 ++++++ drivers/hv/dxgkrnl/ioctl.c | 230 ++++++++++++++++++++++++++++++++++ include/uapi/misc/d3dkmthk.h | 126 +++++++++++++++++++ 5 files changed, 554 insertions(+)
drivers/hv/dxgkrnl/dxgkrnl.h +10 -0
@@ -797,6 +797,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/dxgvmbus.h +38 -0
@@ -418,6 +418,44 @@ struct dxgkvmb_command_flushheaptransitions {struct dxgkvmb_command_vgpu_to_host hdr; }; +struct dxgkvmb_command_freegpuvirtualaddress { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmt_freegpuvirtualaddress args; +}; + +struct dxgkvmb_command_mapgpuvirtualaddress { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dddi_mapgpuvirtualaddress args; +struct d3dkmthandle device; +}; + +struct dxgkvmb_command_mapgpuvirtualaddress_return { +u64 virtual_address; +u64 paging_fence_value; +struct ntstatus status; +}; + +struct dxgkvmb_command_reservegpuvirtualaddress { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dddi_reservegpuvirtualaddress args; +}; + +struct dxgkvmb_command_reservegpuvirtualaddress_return { +u64 virtual_address; +u64 paging_fence_value; +}; + +struct dxgkvmb_command_updategpuvirtualaddress { +struct dxgkvmb_command_vgpu_to_host hdr; +u64 fence_value; +struct d3dkmthandle device; +struct d3dkmthandle context; +struct d3dkmthandle fence_object; +u32 num_operations; +u32 flags; +struct d3dddi_updategpuvirtualaddress_operation operations[1 ]; +}; +struct dxgkvmb_command_queryclockcalibration {struct dxgkvmb_command_vgpu_to_host hdr;struct d3dkmt_queryclockcalibration args;
drivers/hv/dxgkrnl/ioctl.c +230 -0
260 lines not on this page · raw message
include/uapi/misc/d3dkmthk.h +126 -0
156 lines not on this page · raw message
Signature · 1 line
2.35.1
PATCH v3 30/30 drivers: hv: dxgkrnl: Add support to map guest pages by host
In reply to Iouri TarassovImplement support for mapping guest memory pages by the host. This removes hyper-v limitations of using GPADL (guest physical address list).
Dxgkrnl uses hyper-v GPADLs to share guest system memory with the host. This method has limitations:
- a single GPADL can represent only ~32MB of memory
- there is a limit of how much memory the total size of GPADLs in a VM can represent.
To avoid these limitations the host implemented mapping guest memory pages. Presence of this support is determined by reading PCI config space. When the support is enabled, dxgkrnl does not use GPADLs and instead uses the following code flow:
- memory pages of an existing system memory buffer are pinned
- PFNs of the pages are sent to the host via a VM bus message
- the host maps the PFNs to get access to the memory
--- 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 | 10 +++ drivers/hv/dxgkrnl/ioctl.c | 7 +- drivers/hv/dxgkrnl/misc.c | 6 ++ drivers/hv/dxgkrnl/misc.h | 1 + 8 files changed, 153 insertions(+), 50 deletions(-)
drivers/hv/dxgkrnl/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the hyper-v compute device driver (dxgkrnl). obj-$(CONFIG_DXGKRNL) += dxgkrnl.o -dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o +dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
drivers/hv/dxgkrnl/dxgkrnl.h +2 -0
@@ -305,6 +305,7 @@ struct dxgglobal {bool pci_registered;bool global_channel_initialized;bool async_msg_enabled; +bool map_guest_pages_enabled; };extern struct dxgglobal *dxgglobal;
@@ -837,6 +838,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
@@ -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 +10 -0
@@ -234,6 +234,16 @@ struct dxgkvmb_command_setexistingsysmemstore {u32 gpadl; }; +/* Returns ntstatus */ +struct dxgkvmb_command_setexistingsysmempages { +struct dxgkvmb_command_vgpu_to_host hdr; +struct d3dkmthandle device; +struct d3dkmthandle allocation; +u32 num_pages; +u32 alloc_offset_in_pages; +/* u64 pfn_array[num_pages] */ +}; +struct dxgkvmb_command_createprocess {struct dxgkvmb_command_vm_to_host hdr;void *process;
drivers/hv/dxgkrnl/ioctl.c +1 -6
@@ -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;
@@ -3536,7 +3531,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
@@ -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
@@ -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
Wei Liu
maintainerRe: [PATCH v3 30/30] drivers: hv: dxgkrnl: Add support to map guest pages by host
On Tue, Mar 01, 2022 at 11:46:17AM -0800, Iouri Tarassov wrote:
[...]
drivers/hv/dxgkrnl/dxgvmbus.c int create_existing_sysmem(struct dxgdevice *device, · line 1399
Quoted 5 lines
drivers/hv/dxgkrnl/dxgvmbus.c +1
-0@@ -1393,6 +1396,7 @@ int create_existing_sysmem(struct dxgdevice *device,pr_debug (" Alloc size: %lld" , alloc_size); dxgalloc->cpu_address = (void *)sysmem; +
Well this is just adding a blank line. Please avoid changes like this...
Thanks,
Wei.
Re: [PATCH v3 01/30] drivers: hv: dxgkrnl: Add virtual compute device VM bus channel guids
In reply to Iouri TarassovQuoted 1 line · Iouri Tarassov
Add VM bus channel guids, which are used by hyper-v virtual
"VMBus"
Quoted 1 line
compute device driver.
"Hyper-V"
Quoted 2 lines
Signed-off-by Iouri Tarassov <[email protected]>
This patch is trivially correct so with the names fixed.
Quoted 34 lines
--- include/linux/hyperv.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)include/linux/hyperv.h +16
-0@@ -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} Signature · 1 line
2.35.1
Hi Iouri,
this still does not address what native API this matches.
As lonk as this is a just a shim to call functionality not natively availabe on Linux: NAK.
Wei Liu
maintainerHi Iouri
I've gone through the whole series. A large portion of the series is about graphics stuff which is out of my wheelhouse.
I have two general comments here.
There seems to be an excessive amount pr_debug / pr_err in code. Please try to reduce their number a bit.
For memory allocation you always use vzalloc, however large or small the allocation may be. Why not use kzalloc for smaller allocations?
Thanks,
Wei.