Skip to content

Commit 8aa6caf

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 <[email protected]>
1 parent 606198e commit 8aa6caf

File tree

4 files changed

+124
-30
lines changed

4 files changed

+124
-30
lines changed

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
@@ -1307,15 +1307,18 @@ int create_existing_sysmem(struct dxgdevice *device,
13071307
void *kmem = NULL;
13081308
int ret = 0;
13091309
struct dxgkvmb_command_setexistingsysmemstore *set_store_command;
1310+
struct dxgkvmb_command_setexistingsysmempages *set_pages_command;
13101311
u64 alloc_size = host_alloc->allocation_size;
13111312
u32 npages = alloc_size >> PAGE_SHIFT;
13121313
struct dxgvmbusmsg msg = {.hdr = NULL};
1313-
1314-
ret = init_message(&msg, device->adapter, device->process,
1315-
sizeof(*set_store_command));
1316-
if (ret)
1317-
goto cleanup;
1318-
set_store_command = (void *)msg.msg;
1314+
const u32 max_pfns_in_message =
1315+
(DXG_MAX_VM_BUS_PACKET_SIZE - sizeof(*set_pages_command) -
1316+
PAGE_SIZE) / sizeof(__u64);
1317+
u32 alloc_offset_in_pages = 0;
1318+
struct page **page_in;
1319+
u64 *pfn;
1320+
u32 pages_to_send;
1321+
u32 i;
13191322

13201323
/*
13211324
* Create a guest physical address list and set it as the allocation
@@ -1326,6 +1329,7 @@ int create_existing_sysmem(struct dxgdevice *device,
13261329
dev_dbg(dxgglobaldev, " Alloc size: %lld", alloc_size);
13271330

13281331
dxgalloc->cpu_address = (void *)sysmem;
1332+
13291333
dxgalloc->pages = vzalloc(npages * sizeof(void *));
13301334
if (dxgalloc->pages == NULL) {
13311335
pr_err("failed to allocate pages");
@@ -1343,31 +1347,79 @@ int create_existing_sysmem(struct dxgdevice *device,
13431347
ret = -ENOMEM;
13441348
goto cleanup;
13451349
}
1346-
kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
1347-
if (kmem == NULL) {
1348-
pr_err("vmap failed");
1349-
ret = -ENOMEM;
1350-
goto cleanup;
1351-
}
1352-
ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
1353-
alloc_size, &dxgalloc->gpadl);
1354-
if (ret1) {
1355-
pr_err("establish_gpadl failed: %d", ret1);
1356-
ret = -ENOMEM;
1357-
goto cleanup;
1358-
}
1359-
dev_dbg(dxgglobaldev, "New gpadl %d", dxgalloc->gpadl);
1350+
if (!dxgglobal->map_guest_pages_enabled) {
1351+
ret = init_message(&msg, device->adapter, device->process,
1352+
sizeof(*set_store_command));
1353+
if (ret)
1354+
goto cleanup;
1355+
set_store_command = (void *)msg.msg;
13601356

1361-
command_vgpu_to_host_init2(&set_store_command->hdr,
1362-
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
1363-
device->process->host_handle);
1364-
set_store_command->device = device->handle;
1365-
set_store_command->device = device->handle;
1366-
set_store_command->allocation = host_alloc->allocation;
1367-
set_store_command->gpadl = dxgalloc->gpadl;
1368-
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size);
1369-
if (ret < 0)
1370-
pr_err("failed to set existing store: %x", ret);
1357+
kmem = vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL);
1358+
if (kmem == NULL) {
1359+
pr_err("vmap failed");
1360+
ret = -ENOMEM;
1361+
goto cleanup;
1362+
}
1363+
ret1 = vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem,
1364+
alloc_size, &dxgalloc->gpadl);
1365+
if (ret1) {
1366+
pr_err("establish_gpadl failed: %d", ret1);
1367+
ret = -ENOMEM;
1368+
goto cleanup;
1369+
}
1370+
dev_dbg(dxgglobaldev, "New gpadl %d", dxgalloc->gpadl);
1371+
1372+
command_vgpu_to_host_init2(&set_store_command->hdr,
1373+
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE,
1374+
device->process->host_handle);
1375+
set_store_command->device = device->handle;
1376+
set_store_command->allocation = host_alloc->allocation;
1377+
set_store_command->gpadl = dxgalloc->gpadl;
1378+
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr,
1379+
msg.size);
1380+
if (ret < 0)
1381+
pr_err("failed to set existing store: %x", ret);
1382+
} else {
1383+
/*
1384+
* Send the list of the allocation PFNs to the host. The host
1385+
* will map the pages for GPU access.
1386+
*/
1387+
1388+
ret = init_message(&msg, device->adapter, device->process,
1389+
sizeof(*set_pages_command) +
1390+
max_pfns_in_message * sizeof(u64));
1391+
if (ret)
1392+
goto cleanup;
1393+
set_pages_command = (void *)msg.msg;
1394+
command_vgpu_to_host_init2(&set_pages_command->hdr,
1395+
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES,
1396+
device->process->host_handle);
1397+
set_pages_command->device = device->handle;
1398+
set_pages_command->allocation = host_alloc->allocation;
1399+
1400+
page_in = dxgalloc->pages;
1401+
while (alloc_offset_in_pages < npages) {
1402+
pfn = (u64 *)((char *)msg.msg +
1403+
sizeof(*set_pages_command));
1404+
pages_to_send = min(npages - alloc_offset_in_pages,
1405+
max_pfns_in_message);
1406+
set_pages_command->num_pages = pages_to_send;
1407+
set_pages_command->alloc_offset_in_pages =
1408+
alloc_offset_in_pages;
1409+
1410+
for (i = 0; i < pages_to_send; i++)
1411+
*pfn++ = page_to_pfn(*page_in++);
1412+
1413+
ret = dxgvmb_send_sync_msg_ntstatus(msg.channel,
1414+
msg.hdr,
1415+
msg.size);
1416+
if (ret < 0) {
1417+
pr_err("failed to set existing pages: %x", ret);
1418+
break;
1419+
}
1420+
alloc_offset_in_pages += pages_to_send;
1421+
}
1422+
}
13711423

13721424
cleanup:
13731425
if (kmem)

drivers/hv/dxgkrnl/dxgvmbus.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ enum dxgkvmb_commandtype {
139139
DXGK_VMBCOMMAND_GETCONTEXTSCHEDULINGPRIORITY = 61,
140140
DXGK_VMBCOMMAND_QUERYCLOCKCALIBRATION = 62,
141141
DXGK_VMBCOMMAND_QUERYRESOURCEINFO = 64,
142+
DXGK_VMBCOMMAND_LOGEVENT = 65,
143+
DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES = 66,
142144
DXGK_VMBCOMMAND_INVALID
143145
};
144146

@@ -245,6 +247,16 @@ struct dxgkvmb_command_setexistingsysmemstore {
245247
u32 gpadl;
246248
};
247249

250+
/* Returns ntstatus */
251+
struct dxgkvmb_command_setexistingsysmempages {
252+
struct dxgkvmb_command_vgpu_to_host hdr;
253+
struct d3dkmthandle device;
254+
struct d3dkmthandle allocation;
255+
u32 num_pages;
256+
u32 alloc_offset_in_pages;
257+
/* u64 pfn_array[num_pages] */
258+
};
259+
248260
struct dxgkvmb_command_createprocess {
249261
struct dxgkvmb_command_vm_to_host hdr;
250262
void *process;

0 commit comments

Comments
 (0)