Skip to content

Commit 753ed3c

Browse files
Iouri Tarassovchessturo
authored andcommitted
drivers: hv: dxgkrnl: Add support to map guest pages by host
Implement support for mapping guest memory pages by the host. This removes hyper-v limitations of using GPADL (guest physical address list). Dxgkrnl uses hyper-v GPADLs to share guest system memory with the host. This method has limitations: - a single GPADL can represent only ~32MB of memory - there is a limit of how much memory the total size of GPADLs in a VM can represent. To avoid these limitations the host implemented mapping guest memory pages. Presence of this support is determined by reading PCI config space. When the support is enabled, dxgkrnl does not use GPADLs and instead uses the following code flow: - memory pages of an existing system memory buffer are pinned - PFNs of the pages are sent to the host via a VM bus message - the host maps the PFNs to get access to the memory Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com> [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
1 parent fcb44b5 commit 753ed3c

6 files changed

Lines changed: 129 additions & 35 deletions

File tree

drivers/hv/dxgkrnl/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Makefile for the hyper-v compute device driver (dxgkrnl).
33

44
obj-$(CONFIG_DXGKRNL) += dxgkrnl.o
5-
dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o
5+
dxgkrnl-y := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o dxgprocess.o

drivers/hv/dxgkrnl/dxgkrnl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ struct dxgglobal {
316316
bool misc_registered;
317317
bool pci_registered;
318318
bool vmbus_registered;
319+
bool map_guest_pages_enabled;
319320
};
320321

321322
static inline struct dxgglobal *dxggbl(void)

drivers/hv/dxgkrnl/dxgmodule.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ void dxgglobal_remove_host_event(struct dxghostevent *event)
147147

148148
void signal_host_cpu_event(struct dxghostevent *eventhdr)
149149
{
150-
struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
150+
struct dxghosteventcpu *event = (struct dxghosteventcpu *)eventhdr;
151151

152152
if (event->remove_from_list ||
153153
event->destroy_after_signal) {
@@ -426,7 +426,11 @@ const struct file_operations dxgk_fops = {
426426
#define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
427427
sizeof(u32))
428428

429-
/* The guest writes its capabilities to this address */
429+
/* The host caps (dxgk_vmbus_hostcaps) */
430+
#define DXGK_VMBUS_HOSTCAPS_OFFSET (DXGK_VMBUS_VGPU_LUID_OFFSET + \
431+
sizeof(struct winluid))
432+
433+
/* The guest writes its capavilities to this adderss */
430434
#define DXGK_VMBUS_GUESTCAPS_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
431435
sizeof(u32))
432436

@@ -441,6 +445,23 @@ struct dxgk_vmbus_guestcaps {
441445
};
442446
};
443447

448+
/*
449+
* The structure defines features, supported by the host.
450+
*
451+
* map_guest_memory
452+
* Host can map guest memory pages, so the guest can avoid using GPADLs
453+
* to represent existing system memory allocations.
454+
*/
455+
struct dxgk_vmbus_hostcaps {
456+
union {
457+
struct {
458+
u32 map_guest_memory : 1;
459+
u32 reserved : 31;
460+
};
461+
u32 host_caps;
462+
};
463+
};
464+
444465
/*
445466
* A helper function to read PCI config space.
446467
*/
@@ -475,6 +496,7 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
475496
struct winluid vgpu_luid = {};
476497
struct dxgk_vmbus_guestcaps guest_caps = {.wsl2 = 1};
477498
struct dxgglobal *dxgglobal = dxggbl();
499+
struct dxgk_vmbus_hostcaps host_caps = {};
478500

479501
mutex_lock(&dxgglobal->device_mutex);
480502

@@ -503,6 +525,13 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
503525
if (ret)
504526
goto cleanup;
505527

528+
ret = pci_read_config_dword(dev, DXGK_VMBUS_HOSTCAPS_OFFSET,
529+
&host_caps.host_caps);
530+
if (ret == 0) {
531+
if (host_caps.map_guest_memory)
532+
dxgglobal->map_guest_pages_enabled = true;
533+
}
534+
506535
if (dxgglobal->vmbus_ver > DXGK_VMBUS_INTERFACE_VERSION)
507536
dxgglobal->vmbus_ver = DXGK_VMBUS_INTERFACE_VERSION;
508537
}

drivers/hv/dxgkrnl/dxgvmbus.c

Lines changed: 85 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,15 +1383,19 @@ int create_existing_sysmem(struct dxgdevice *device,
13831383
void *kmem = NULL;
13841384
int ret = 0;
13851385
struct dxgkvmb_command_setexistingsysmemstore *set_store_command;
1386+
struct dxgkvmb_command_setexistingsysmempages *set_pages_command;
13861387
u64 alloc_size = host_alloc->allocation_size;
13871388
u32 npages = alloc_size >> PAGE_SHIFT;
13881389
struct dxgvmbusmsg msg = {.hdr = NULL};
1389-
1390-
ret = init_message(&msg, device->adapter, device->process,
1391-
sizeof(*set_store_command));
1392-
if (ret)
1393-
goto cleanup;
1394-
set_store_command = (void *)msg.msg;
1390+
const u32 max_pfns_in_message =
1391+
(DXG_MAX_VM_BUS_PACKET_SIZE - sizeof(*set_pages_command) -
1392+
PAGE_SIZE) / sizeof(__u64);
1393+
u32 alloc_offset_in_pages = 0;
1394+
struct page **page_in;
1395+
u64 *pfn;
1396+
u32 pages_to_send;
1397+
u32 i;
1398+
struct dxgglobal *dxgglobal = dxggbl();
13951399

13961400
/*
13971401
* Create a guest physical address list and set it as the allocation
@@ -1402,6 +1406,7 @@ int create_existing_sysmem(struct dxgdevice *device,
14021406
DXG_TRACE("Alloc size: %lld", alloc_size);
14031407

14041408
dxgalloc->cpu_address = (void *)sysmem;
1409+
14051410
dxgalloc->pages = vzalloc(npages * sizeof(void *));
14061411
if (dxgalloc->pages == NULL) {
14071412
DXG_ERR("failed to allocate pages");
@@ -1419,39 +1424,87 @@ int create_existing_sysmem(struct dxgdevice *device,
14191424
ret = -ENOMEM;
14201425
goto cleanup;
14211426
}
1422-
kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
1423-
if (kmem == NULL) {
1424-
DXG_ERR("vmap failed");
1425-
ret = -ENOMEM;
1426-
goto cleanup;
1427-
}
1428-
ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
1429-
alloc_size, &dxgalloc->gpadl);
1430-
if (ret1) {
1431-
DXG_ERR("establish_gpadl failed: %d", ret1);
1432-
ret = -ENOMEM;
1433-
goto cleanup;
1434-
}
1427+
if (!dxgglobal->map_guest_pages_enabled) {
1428+
ret = init_message(&msg, device->adapter, device->process,
1429+
sizeof(*set_store_command));
1430+
if (ret)
1431+
goto cleanup;
1432+
set_store_command = (void *)msg.msg;
1433+
1434+
kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
1435+
if (kmem == NULL) {
1436+
DXG_ERR("vmap failed");
1437+
ret = -ENOMEM;
1438+
goto cleanup;
1439+
}
1440+
ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
1441+
alloc_size, &dxgalloc->gpadl);
1442+
if (ret1) {
1443+
DXG_ERR("establish_gpadl failed: %d", ret1);
1444+
ret = -ENOMEM;
1445+
goto cleanup;
1446+
}
14351447
#ifdef _MAIN_KERNEL_
1436-
DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle);
1448+
DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle);
14371449
#else
1438-
DXG_TRACE("New gpadl %d", dxgalloc->gpadl);
1450+
DXG_TRACE("New gpadl %d", dxgalloc->gpadl);
14391451
#endif
14401452

1441-
command_vgpu_to_host_init2(&set_store_command->hdr,
1442-
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
1443-
device->process->host_handle);
1444-
set_store_command->device = device->handle;
1445-
set_store_command->device = device->handle;
1446-
set_store_command->allocation = host_alloc->allocation;
1453+
command_vgpu_to_host_init2(&set_store_command->hdr,
1454+
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
1455+
device->process->host_handle);
1456+
set_store_command->device = device->handle;
1457+
set_store_command->allocation = host_alloc->allocation;
14471458
#ifdef _MAIN_KERNEL_
1448-
set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
1459+
set_store_command->gpadl = dxgalloc->gpadl.gpadl_handle;
14491460
#else
1450-
set_store_command->gpadl = dxgalloc->gpadl;
1461+
set_store_command->gpadl = dxgalloc->gpadl;
14511462
#endif
1452-
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
1453-
if (ret < 0)
1454-
DXG_ERR("failed to set existing store: %x", ret);
1463+
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
1464+
msg.size);
1465+
if (ret < 0)
1466+
DXG_ERR("failed set existing store: %x", ret);
1467+
} else {
1468+
/*
1469+
* Send the list of the allocation PFNs to the host. The host
1470+
* will map the pages for GPU access.
1471+
*/
1472+
1473+
ret = init_message(&msg, device->adapter, device->process,
1474+
sizeof(*set_pages_command) +
1475+
max_pfns_in_message * sizeof(u64));
1476+
if (ret)
1477+
goto cleanup;
1478+
set_pages_command = (void *)msg.msg;
1479+
command_vgpu_to_host_init2(&set_pages_command->hdr,
1480+
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES,
1481+
device->process->host_handle);
1482+
set_pages_command->device = device->handle;
1483+
set_pages_command->allocation = host_alloc->allocation;
1484+
1485+
page_in = dxgalloc->pages;
1486+
while (alloc_offset_in_pages < npages) {
1487+
pfn = (u64 *)((char *)msg.msg +
1488+
sizeof(*set_pages_command));
1489+
pages_to_send = min(npages - alloc_offset_in_pages,
1490+
max_pfns_in_message);
1491+
set_pages_command->num_pages = pages_to_send;
1492+
set_pages_command->alloc_offset_in_pages =
1493+
alloc_offset_in_pages;
1494+
1495+
for (i = 0; i < pages_to_send; i++)
1496+
*pfn++ = page_to_pfn(*page_in++);
1497+
1498+
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel,
1499+
msg.hdr,
1500+
msg.size);
1501+
if (ret < 0) {
1502+
DXG_ERR("failed set existing pages: %x", ret);
1503+
break;
1504+
}
1505+
alloc_offset_in_pages += pages_to_send;
1506+
}
1507+
}
14551508

14561509
cleanup:
14571510
if (kmem)

drivers/hv/dxgkrnl/dxgvmbus.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,16 @@ struct dxgkvmb_command_setexistingsysmemstore {
234234
u32 gpadl;
235235
};
236236

237+
/* Returns ntstatus */
238+
struct dxgkvmb_command_setexistingsysmempages {
239+
struct dxgkvmb_command_vgpu_to_host hdr;
240+
struct d3dkmthandle device;
241+
struct d3dkmthandle allocation;
242+
u32 num_pages;
243+
u32 alloc_offset_in_pages;
244+
/* u64 pfn_array[num_pages] */
245+
};
246+
237247
struct dxgkvmb_command_createprocess {
238248
struct dxgkvmb_command_vm_to_host hdr;
239249
void *process;

drivers/hv/dxgkrnl/misc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ u16 *wcsncpy(u16 *dest, const u16 *src, size_t n)
3535
dest[i - 1] = 0;
3636
return dest;
3737
}
38+

0 commit comments

Comments
 (0)