Skip to content

Commit 9b075b1

Browse files
author
Iouri Tarassov
committed
drivers: hv: dxgkrnl: Implement support for mapping guest pages on the host.
Prior to this change GPADLs were user to represent system memory buffers to the host. GPADL can represent a buffer with max of ~32MB and there is also a limit of total size of GPADLs in a VM. The change makes use of the API on host, which maps guest pages. This API does not have GPADL limitations. Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
1 parent b98b15b commit 9b075b1

3 files changed

Lines changed: 112 additions & 30 deletions

File tree

drivers/hv/dxgkrnl/dxgkrnl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ struct dxgglobal {
306306
bool pci_registered;
307307
bool global_channel_initialized;
308308
bool async_msg_enabled;
309+
bool map_guest_pages_enabled;
309310
};
310311

311312
extern struct dxgglobal *dxgglobal;

drivers/hv/dxgkrnl/dxgmodule.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,9 @@ const struct file_operations dxgk_fops = {
417417
/* Luid of the virtual GPU on the host (struct winluid) */
418418
#define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
419419
sizeof(u32))
420+
/* The host caps (dxgk_vmbus_hostcaps) */
421+
#define DXGK_VMBUS_HOSTCAPS_OFFSET (DXGK_VMBUS_VGPU_LUID_OFFSET + \
422+
sizeof(struct winluid))
420423
/* The guest writes its capavilities to this adderss */
421424
#define DXGK_VMBUS_GUESTCAPS_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \
422425
sizeof(u32))
@@ -431,6 +434,24 @@ struct dxgk_vmbus_guestcaps {
431434
};
432435
};
433436

437+
/*
438+
* The structure defines features, supported by the host.
439+
*
440+
* map_guest_memory
441+
* Host can map guest memory pages, so the guest can avoid using GPADLs
442+
* to represent existing system memory allocations.
443+
*/
444+
struct dxgk_vmbus_hostcaps {
445+
union {
446+
struct {
447+
u32 map_guest_memory : 1;
448+
u32 reserved : 31;
449+
};
450+
u32 host_caps;
451+
};
452+
};
453+
454+
434455
static int dxg_pci_read_dwords(struct pci_dev *dev, int offset, int size,
435456
void *val)
436457
{
@@ -457,6 +478,7 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
457478
u32 vmbus_interface_ver = DXGK_VMBUS_INTERFACE_VERSION;
458479
struct winluid vgpu_luid = {};
459480
struct dxgk_vmbus_guestcaps guest_caps = {.wsl2 = 1};
481+
struct dxgk_vmbus_hostcaps host_caps = {};
460482

461483
mutex_lock(&dxgglobal->device_mutex);
462484

@@ -485,6 +507,13 @@ static int dxg_pci_probe_device(struct pci_dev *dev,
485507
if (ret)
486508
goto cleanup;
487509

510+
ret = pci_read_config_dword(dev, DXGK_VMBUS_HOSTCAPS_OFFSET,
511+
&host_caps.host_caps);
512+
if (ret == 0) {
513+
if (host_caps.map_guest_memory)
514+
dxgglobal->map_guest_pages_enabled = true;
515+
}
516+
488517
if (dxgglobal->vmbus_ver > DXGK_VMBUS_INTERFACE_VERSION)
489518
dxgglobal->vmbus_ver = DXGK_VMBUS_INTERFACE_VERSION;
490519
}

drivers/hv/dxgkrnl/dxgvmbus.c

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,15 +1331,18 @@ int create_existing_sysmem(struct dxgdevice *device,
13311331
void *kmem = NULL;
13321332
int ret = 0;
13331333
struct dxgkvmb_command_setexistingsysmemstore *set_store_command;
1334+
struct dxgkvmb_command_setexistingsysmempages *set_pages_command;
13341335
u64 alloc_size = host_alloc->allocation_size;
13351336
u32 npages = alloc_size >> PAGE_SHIFT;
13361337
struct dxgvmbusmsg msg = {.hdr = NULL};
1337-
1338-
ret = init_message(&msg, device->adapter, device->process,
1339-
sizeof(*set_store_command));
1340-
if (ret)
1341-
goto cleanup;
1342-
set_store_command = (void *)msg.msg;
1338+
const u32 max_pfns_in_message =
1339+
(DXG_MAX_VM_BUS_PACKET_SIZE - sizeof(*set_pages_command) -
1340+
PAGE_SIZE) / sizeof(__u64);
1341+
u32 alloc_offset_in_pages = 0;
1342+
struct page **page_in;
1343+
u64 *pfn;
1344+
u32 pages_to_send;
1345+
u32 i;
13431346

13441347
/*
13451348
* Create a guest physical address list and set it as the allocation
@@ -1350,6 +1353,7 @@ int create_existing_sysmem(struct dxgdevice *device,
13501353
dev_dbg(dxgglobaldev, " Alloc size: %lld", alloc_size);
13511354

13521355
dxgalloc->cpu_address = (void *)sysmem;
1356+
13531357
dxgalloc->pages = vzalloc(npages * sizeof(void *));
13541358
if (dxgalloc->pages == NULL) {
13551359
pr_err("failed to allocate pages");
@@ -1367,31 +1371,79 @@ int create_existing_sysmem(struct dxgdevice *device,
13671371
ret = -ENOMEM;
13681372
goto cleanup;
13691373
}
1370-
kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
1371-
if (kmem == NULL) {
1372-
pr_err("vmap failed");
1373-
ret = -ENOMEM;
1374-
goto cleanup;
1375-
}
1376-
ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
1377-
alloc_size, &dxgalloc->gpadl);
1378-
if (ret1) {
1379-
pr_err("establish_gpadl failed: %d", ret1);
1380-
ret = -ENOMEM;
1381-
goto cleanup;
1382-
}
1383-
dev_dbg(dxgglobaldev, "New gpadl %d", dxgalloc->gpadl);
1374+
if (!dxgglobal->map_guest_pages_enabled) {
1375+
ret = init_message(&msg, device->adapter, device->process,
1376+
sizeof(*set_store_command));
1377+
if (ret)
1378+
goto cleanup;
1379+
set_store_command = (void *)msg.msg;
13841380

1385-
command_vgpu_to_host_init2(&set_store_command->hdr,
1386-
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
1387-
device->process->host_handle);
1388-
set_store_command->device = device->handle;
1389-
set_store_command->device = device->handle;
1390-
set_store_command->allocation = host_alloc->allocation;
1391-
set_store_command->gpadl = dxgalloc->gpadl;
1392-
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
1393-
if (ret < 0)
1394-
pr_err("failed to set existing store: %x", ret);
1381+
kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
1382+
if (kmem == NULL) {
1383+
pr_err("vmap failed");
1384+
ret = -ENOMEM;
1385+
goto cleanup;
1386+
}
1387+
ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
1388+
alloc_size, &dxgalloc->gpadl);
1389+
if (ret1) {
1390+
pr_err("establish_gpadl failed: %d", ret1);
1391+
ret = -ENOMEM;
1392+
goto cleanup;
1393+
}
1394+
dev_dbg(dxgglobaldev, "New gpadl %d", dxgalloc->gpadl);
1395+
1396+
command_vgpu_to_host_init2(&set_store_command->hdr,
1397+
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
1398+
device->process->host_handle);
1399+
set_store_command->device = device->handle;
1400+
set_store_command->allocation = host_alloc->allocation;
1401+
set_store_command->gpadl = dxgalloc->gpadl;
1402+
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
1403+
msg.size);
1404+
if (ret < 0)
1405+
pr_err("failed to set existing store: %x", ret);
1406+
} else {
1407+
/*
1408+
* Send the list of the allocation PFNs to the host. The host
1409+
* will map the pages for GPU access.
1410+
*/
1411+
1412+
ret = init_message(&msg, device->adapter, device->process,
1413+
sizeof(*set_pages_command) +
1414+
max_pfns_in_message * sizeof(u64));
1415+
if (ret)
1416+
goto cleanup;
1417+
set_pages_command = (void *)msg.msg;
1418+
command_vgpu_to_host_init2(&set_pages_command->hdr,
1419+
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES,
1420+
device->process->host_handle);
1421+
set_pages_command->device = device->handle;
1422+
set_pages_command->allocation = host_alloc->allocation;
1423+
1424+
page_in = dxgalloc->pages;
1425+
while (alloc_offset_in_pages < npages) {
1426+
pfn = (u64 *)((char *)msg.msg +
1427+
sizeof(*set_pages_command));
1428+
pages_to_send = min(npages - alloc_offset_in_pages,
1429+
max_pfns_in_message);
1430+
set_pages_command->num_pages = pages_to_send;
1431+
set_pages_command->alloc_offset_in_pages =
1432+
alloc_offset_in_pages;
1433+
1434+
for (i = 0; i < pages_to_send; i++)
1435+
*pfn++ = page_to_pfn(*page_in++);
1436+
1437+
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel,
1438+
msg.hdr,
1439+
msg.size);
1440+
if (ret < 0) {
1441+
pr_err("failed to set existing pages: %x", ret);
1442+
break;
1443+
}
1444+
alloc_offset_in_pages += pages_to_send;
1445+
}
1446+
}
13951447

13961448
cleanup:
13971449
if (kmem)

0 commit comments

Comments
 (0)