Skip to content

Commit ffc60f5

Browse files
author
Iouri Tarassov
committed
drivers: hv: dxgkrnl: Driver initialization and creation of dxgadapter
- Add support for a Hyper-V based vGPU implementation that exposes the DirectX API to Linux userspace. - Handle driver loading, registration for the PCI and VM bus device notifications - Add headers for user mode interfaces, internal driver objects and VM bus communication interface - Handle initialization of VM bus channels and creation of the dxgadapter object - Removed dxg_copy_from_user and dxg_copy_to_user - Connect the dxgkrnl module to the drivers/hv/ makefile and Kconfig. - Create a MAINTAINERS entry PCI driver registration A PCI device is created for each virtual GPU (vGPU) device, projected by the host. The device vendor is PCI_VENDOR_ID_MICROSOFT and device id is PCI_DEVICE_ID_VIRTUAL_RENDER. dxg_pci_probe_device handles arrival of such devices and it creates dxgadapter objects. The PCI config space of the vGPU device has luid of the corresponding per GPU VM bus channel. This is how the adapters are linked to VM bus channels. dxgadapter initialization A dxgadapter object represents a virtual GPU, projected to the VM by the host. This object can start functioning only when the global VM bus channel and the corresponding per vGPU VM bus channel are initialized in the guest. Notifications about arrival of vGPU PCI device and VM bus channels can happen in any order. Therefore, the initial dxgadapter object state is DXGADAPTER_STATE_WAITING_VMBUS. A list of VM bus channels and a list of dxgadapter objects are created. When dxgkrnl is notified about a VM bus channel arrival, if tries to start all adapters, which are not started yet. VM bus interface version is exchanged by reading/writing the PCI config space of the vGPU device. Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
1 parent 2c85ebc commit ffc60f5

18 files changed

Lines changed: 5879 additions & 0 deletions

File tree

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8190,6 +8190,12 @@ F: Documentation/devicetree/bindings/mtd/ti,am654-hbmc.txt
81908190
F: drivers/mtd/hyperbus/
81918191
F: include/linux/mtd/hyperbus.h
81928192

8193+
Hyper-V vGPU DRIVER
8194+
M: Iouri Tarassov <iourit@microsoft.com>
8195+
L: linux-hyperv@vger.kernel.org
8196+
S: Supported
8197+
F: drivers/hv/dxgkrnl/
8198+
81938199
HYPERVISOR VIRTUAL CONSOLE DRIVER
81948200
L: linuxppc-dev@lists.ozlabs.org
81958201
S: Odd Fixes

drivers/hv/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ config HYPERV_BALLOON
2626
help
2727
Select this option to enable Hyper-V Balloon driver.
2828

29+
source "drivers/hv/dxgkrnl/Kconfig"
30+
2931
endmenu

drivers/hv/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
obj-$(CONFIG_HYPERV) += hv_vmbus.o
33
obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o
44
obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
5+
obj-$(CONFIG_DXGKRNL) += dxgkrnl/
56

67
CFLAGS_hv_trace.o = -I$(src)
78
CFLAGS_hv_balloon.o = -I$(src)

drivers/hv/dxgkrnl/Kconfig

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#
2+
# dxgkrnl configuration
3+
#
4+
5+
config DXGKRNL
6+
tristate "Microsoft Paravirtualized GPU support"
7+
depends on HYPERV
8+
depends on 64BIT || COMPILE_TEST
9+
help
10+
This driver supports paravirtualized virtual compute devices, exposed
11+
by Microsoft Hyper-V when Linux is running inside of a virtual machine
12+
hosted by Windows. The virtual machines needs to be configured to use
13+
host compute adapters. The driver name is dxgkrnl.
14+
15+
An example of such virtual machine is a Windows Subsystem for
16+
Linux container. When such container is instantiated, the Windows host
17+
assigns compatible host GPU adapters to the container. The corresponding
18+
virtual GPU devices appear on the PCI bus in the container. These
19+
devices are enumerated and accessed by this driver.
20+
21+
Communications with the driver are done by using the Microsoft libdxcore
22+
library, which translates the D3DKMT interface
23+
<https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/d3dkmthk/>
24+
to the driver IOCTLs. The virtual GPU devices are paravirtualized,
25+
which means that access to the hardware is done in the host. The driver
26+
communicates with the host using Hyper-V VM bus communication channels.

drivers/hv/dxgkrnl/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Makefile for the Linux video drivers.
3+
4+
obj-$(CONFIG_DXGKRNL) += dxgkrnl.o
5+
dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o

drivers/hv/dxgkrnl/dxgadapter.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
/*
4+
* Copyright (c) 2019, Microsoft Corporation.
5+
*
6+
* Author:
7+
* Iouri Tarassov <iourit@linux.microsoft.com>
8+
*
9+
* Dxgkrnl Graphics Driver
10+
* Implementation of dxgadapter and its objects
11+
*
12+
*/
13+
14+
#include <linux/module.h>
15+
#include <linux/hyperv.h>
16+
#include <linux/pagemap.h>
17+
#include <linux/eventfd.h>
18+
19+
#include "dxgkrnl.h"
20+
21+
#undef pr_fmt
22+
#define pr_fmt(fmt) "dxgk:err: " fmt
23+
#undef dev_fmt
24+
#define dev_fmt(fmt) "dxgk: " fmt
25+
26+
int dxgadapter_set_vmbus(struct dxgadapter *adapter, struct hv_device *hdev)
27+
{
28+
int ret;
29+
30+
guid_to_luid(&hdev->channel->offermsg.offer.if_instance,
31+
&adapter->luid);
32+
dev_dbg(dxgglobaldev, "%s: %x:%x %p %pUb\n",
33+
__func__, adapter->luid.b, adapter->luid.a, hdev->channel,
34+
&hdev->channel->offermsg.offer.if_instance);
35+
36+
ret = dxgvmbuschannel_init(&adapter->channel, hdev);
37+
if (ret)
38+
goto cleanup;
39+
40+
adapter->channel.adapter = adapter;
41+
adapter->hv_dev = hdev;
42+
43+
ret = dxgvmb_send_open_adapter(adapter);
44+
if (ret < 0) {
45+
pr_err("dxgvmb_send_open_adapter failed: %d\n", ret);
46+
goto cleanup;
47+
}
48+
49+
ret = dxgvmb_send_get_internal_adapter_info(adapter);
50+
if (ret < 0)
51+
pr_err("get_internal_adapter_info failed: %d", ret);
52+
53+
cleanup:
54+
if (ret)
55+
dev_dbg(dxgglobaldev, "err: %s %d", __func__, ret);
56+
return ret;
57+
}
58+
59+
void dxgadapter_start(struct dxgadapter *adapter)
60+
{
61+
struct dxgvgpuchannel *ch = NULL;
62+
struct dxgvgpuchannel *entry;
63+
int ret;
64+
65+
dev_dbg(dxgglobaldev, "%s %x-%x",
66+
__func__, adapter->luid.a, adapter->luid.b);
67+
68+
/* Find the corresponding vGPU vm bus channel */
69+
list_for_each_entry(entry, &dxgglobal->vgpu_ch_list_head,
70+
vgpu_ch_list_entry) {
71+
if (memcmp(&adapter->luid,
72+
&entry->adapter_luid,
73+
sizeof(struct winluid)) == 0) {
74+
ch = entry;
75+
break;
76+
}
77+
}
78+
if (ch == NULL) {
79+
dev_dbg(dxgglobaldev, "%s vGPU chanel is not ready", __func__);
80+
return;
81+
}
82+
83+
/* The global channel is initialized when the first adapter starts */
84+
if (!dxgglobal->global_channel_initialized) {
85+
ret = dxgglobal_init_global_channel();
86+
if (ret) {
87+
dxgglobal_destroy_global_channel();
88+
return;
89+
}
90+
dxgglobal->global_channel_initialized = true;
91+
}
92+
93+
/* Initialize vGPU vm bus channel */
94+
ret = dxgadapter_set_vmbus(adapter, ch->hdev);
95+
if (ret) {
96+
pr_err("Failed to start adapter %p", adapter);
97+
adapter->adapter_state = DXGADAPTER_STATE_STOPPED;
98+
return;
99+
}
100+
101+
adapter->adapter_state = DXGADAPTER_STATE_ACTIVE;
102+
dev_dbg(dxgglobaldev, "%s Adapter started %p", __func__, adapter);
103+
}
104+
105+
void dxgadapter_stop(struct dxgadapter *adapter)
106+
{
107+
struct dxgprocess_adapter *entry;
108+
bool adapter_stopped = false;
109+
110+
down_write(&adapter->core_lock);
111+
if (!adapter->stopping_adapter)
112+
adapter->stopping_adapter = true;
113+
else
114+
adapter_stopped = true;
115+
up_write(&adapter->core_lock);
116+
117+
if (adapter_stopped)
118+
return;
119+
120+
dxgglobal_acquire_process_adapter_lock();
121+
122+
list_for_each_entry(entry, &adapter->adapter_process_list_head,
123+
adapter_process_list_entry) {
124+
dxgprocess_adapter_stop(entry);
125+
}
126+
127+
dxgglobal_release_process_adapter_lock();
128+
129+
if (dxgadapter_acquire_lock_exclusive(adapter) == 0) {
130+
dxgvmb_send_close_adapter(adapter);
131+
dxgadapter_release_lock_exclusive(adapter);
132+
}
133+
dxgvmbuschannel_destroy(&adapter->channel);
134+
135+
adapter->adapter_state = DXGADAPTER_STATE_STOPPED;
136+
}
137+
138+
void dxgadapter_release(struct kref *refcount)
139+
{
140+
struct dxgadapter *adapter;
141+
142+
adapter = container_of(refcount, struct dxgadapter, adapter_kref);
143+
dev_dbg(dxgglobaldev, "%s %p\n", __func__, adapter);
144+
vfree(adapter);
145+
}
146+
147+
bool dxgadapter_is_active(struct dxgadapter *adapter)
148+
{
149+
return adapter->adapter_state == DXGADAPTER_STATE_ACTIVE;
150+
}
151+
152+
int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter)
153+
{
154+
down_write(&adapter->core_lock);
155+
if (adapter->adapter_state != DXGADAPTER_STATE_ACTIVE) {
156+
dxgadapter_release_lock_exclusive(adapter);
157+
return -ENODEV;
158+
}
159+
return 0;
160+
}
161+
162+
void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter)
163+
{
164+
down_write(&adapter->core_lock);
165+
}
166+
167+
void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter)
168+
{
169+
up_write(&adapter->core_lock);
170+
}
171+
172+
int dxgadapter_acquire_lock_shared(struct dxgadapter *adapter)
173+
{
174+
down_read(&adapter->core_lock);
175+
if (adapter->adapter_state == DXGADAPTER_STATE_ACTIVE)
176+
return 0;
177+
dxgadapter_release_lock_shared(adapter);
178+
return -ENODEV;
179+
}
180+
181+
void dxgadapter_release_lock_shared(struct dxgadapter *adapter)
182+
{
183+
up_read(&adapter->core_lock);
184+
}
185+
186+
void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info)
187+
{
188+
/* Placeholder */
189+
}

0 commit comments

Comments
 (0)