From nobody Mon Apr 6 10:42:02 2026 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E920A3FBEA4 for ; Thu, 19 Mar 2026 20:25:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951952; cv=none; b=ekUO6c2N7VfQuodXGfPU4hHKQGyFAf8TafvCV32lB969lZWA/rPrmTHRJM7QDGNT9utvwL4sYOis6QXP+Tg28QdaGeOXuvfLs6lLktITC935mMwhfieLilFmNSNWOLn/X+6mxMM36tikXT+UlM1F5nC+PyisRv2vhnqN/BzjF9A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951952; c=relaxed/simple; bh=0mnqW+0YxMPWWQ5hYRM9j1JibATge5yEVOcZ4JbBf18=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Zd+PvINAUeXNMvoo187XactTB75SMc6aXtMEApRaAF5Lrki4gcE0RfPYxcx1E49sTf0vRq9p3GjXWAMw9opJVimHwvMpNGBHDTzNt06TH9R1WNvvbQjgkxsvbiYSs/hv4px/1WO9xGSpUSL6m4KJ//NJ4xky/QdGzRNp1dB2nZ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Bh8HIKvn; arc=none smtp.client-ip=209.85.221.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Bh8HIKvn" Received: by mail-wr1-f42.google.com with SMTP id ffacd0b85a97d-43b40003d13so878630f8f.2 for ; Thu, 19 Mar 2026 13:25:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951946; x=1774556746; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wzkntaQrinqqPXBhUAC5ve0qVCkj/uMJtIw3Tw3VCWE=; b=Bh8HIKvn+bkd9eZgWfGIy3JOhwXPb5sSZQ9lCaZ6wHRYb6V/VxswkhRZqFcofbYVdq KY3rLjSXOcxnu3RquP/PQNS5qvN/i3+sp7BUVGlKjjLCOulyE443U20R2tJQPtWuzB2X bx5n8O0ZaD2CPCmAgb2kpNPT3lTAR7Uatez2xd3gQGWp02Vi58rOofL6dp1Zt11ZrTgs 68W6qefD2clUynPXPowSUfYitKk82ulUXaowuNnjhNtDB2JfwCLADs74xv68vxZaB3Vr dFLu2ABCkhr8NkucWRrFNpIkp8xSo8Okg9E+tJgKGN9b+nvaRGNZkJEDuEgRKLofnBm6 1Nug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951946; x=1774556746; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=wzkntaQrinqqPXBhUAC5ve0qVCkj/uMJtIw3Tw3VCWE=; b=Luh8Xgg9dSSpqlgjyzxWo7N71bCBKJQAzSf9/xaKWWV0xzG7zHjpwGuNbSP8+Yn1TF 0aOe6QGPvtkdCqepDQr4vbitDb2VKPHwsqCqbbQY4jrwGIACGebJ7eFWufOsubXa667x v+FNs+T9qLchtxy83S8niahHkt38DcGn3a16RUyYK775o3j367GiyNo+EAuCuVu/1UVS 05nibkjdKbyxx6KZhrhoTrPykisijA3IYgtNySlB3s/btstBMqFyA2p1zmaCYkcIjLDY tSFj9gtC6b6ahnTp4Y8zv6kTTRV5ptERUYsEBQq4a9ZzwIg048665eUt/bEmxVx2blTM yUcQ== X-Gm-Message-State: AOJu0Yw5Yprp0hLfwIVUZo1dt876PB6M2OKioxVdaBA4nC7CaGHPHgkv zXjDp3rBdn28nfUD4URlKMvbqeE5S7HHp/y9kag3dsGX2iGAQnmIdL+f X-Gm-Gg: ATEYQzyhO7y0T32PT6Eup/c1mLv1GUpRLCz/iAbdHU2NQD2It1WTtVxtjTxQN3vNAL6 a6OTDDd+QeJ9gGkqj/KTEZP1zzViF9wfp323TaG8kjZ+AKvmAyupJDRrtnZ5Tm9iDK3/U6rWvOJ 656Po0Dhu+DJQRgJE5L2j/DigwM4CFBZm2YIfMjHnjGQhe/nRcH8n1cNTlN5NmLzR2on09DR89f qZ5kKu4NVp5ZfOq37nXfdW30pavj2ay2rzVHMuqDR2c0luaZu2ciTyXeMP/451Yu5EZiDYtDAiZ vXeCuxaDofN6hEWdmoMVmFnfggLcsy2WErKHrQiwCkFbEAMXQr01H9wPOYedLuYBcYTovjasU07 WfR6+ovzxs/bDDT5cj26Jjv1Cy4OlBTiMPTFUVcI4hA3j8iYlfLxW2njhzLcTUWedxDDYomFi8N DvnAfWJq5XnI/w9ZY7wLftV2v1L4DQlTBxm++c1OsuNBoRReLR X-Received: by 2002:a5d:64c6:0:b0:439:df03:f300 with SMTP id ffacd0b85a97d-43b6428178emr1154879f8f.40.1773951945847; Thu, 19 Mar 2026 13:25:45 -0700 (PDT) Received: from LQ5W56KC4T ([2001:8a0:672f:7800:e0e1:55cd:f0b:b1e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b644ae16fsm1347544f8f.8.2026.03.19.13.25.44 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:45 -0700 (PDT) From: Eric Curtin X-Google-Original-From: Eric Curtin To: linux-hyperv@vger.kernel.org Cc: linux-kernel@vger.kernel.org, iourit@linux.microsoft.com, wei.liu@kernel.org, decui@microsoft.com, haiyangz@microsoft.com Subject: [PATCH 28/55] drivers: hv: dxgkrnl: Add support to map guest pages by host Date: Thu, 19 Mar 2026 20:24:42 +0000 Message-ID: <20260319202509.63802-29-eric.curtin@docker.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319202509.63802-1-eric.curtin@docker.com> References: <20260319202509.63802-1-eric.curtin@docker.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Iouri Tarassov 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 [kms: forward port to 6.6 from 6.1. No code changes made.] Signed-off-by: Kelsey Steele --- drivers/hv/dxgkrnl/Makefile | 2 +- drivers/hv/dxgkrnl/dxgkrnl.h | 1 + drivers/hv/dxgkrnl/dxgmodule.c | 33 +++++++++- drivers/hv/dxgkrnl/dxgvmbus.c | 117 ++++++++++++++++++++++++--------- drivers/hv/dxgkrnl/dxgvmbus.h | 10 +++ drivers/hv/dxgkrnl/misc.c | 1 + 6 files changed, 129 insertions(+), 35 deletions(-) diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile index 9d821e83448a..fc85a47a6ad5 100644 --- a/drivers/hv/dxgkrnl/Makefile +++ b/drivers/hv/dxgkrnl/Makefile @@ -2,4 +2,4 @@ # Makefile for the hyper-v compute device driver (dxgkrnl). =20 obj-$(CONFIG_DXGKRNL) +=3D dxgkrnl.o -dxgkrnl-y :=3D dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o = dxgprocess.o +dxgkrnl-y :=3D dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o dxgvmbus.o d= xgprocess.o diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index 93bc9b41aa41..091dbe999d33 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -316,6 +316,7 @@ struct dxgglobal { bool misc_registered; bool pci_registered; bool vmbus_registered; + bool map_guest_pages_enabled; }; =20 static inline struct dxgglobal *dxggbl(void) diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c index 5c364a46b65f..b1b612b90fc1 100644 --- a/drivers/hv/dxgkrnl/dxgmodule.c +++ b/drivers/hv/dxgkrnl/dxgmodule.c @@ -147,7 +147,7 @@ void dxgglobal_remove_host_event(struct dxghostevent *e= vent) =20 void signal_host_cpu_event(struct dxghostevent *eventhdr) { - struct dxghosteventcpu *event =3D (struct dxghosteventcpu *)eventhdr; + struct dxghosteventcpu *event =3D (struct dxghosteventcpu *)eventhdr; =20 if (event->remove_from_list || event->destroy_after_signal) { @@ -426,7 +426,11 @@ const struct file_operations dxgk_fops =3D { #define DXGK_VMBUS_VGPU_LUID_OFFSET (DXGK_VMBUS_VERSION_OFFSET + \ sizeof(u32)) =20 -/* The guest writes its capabilities to this address */ +/* 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)) =20 @@ -441,6 +445,23 @@ struct dxgk_vmbus_guestcaps { }; }; =20 +/* + * 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. */ @@ -475,6 +496,7 @@ static int dxg_pci_probe_device(struct pci_dev *dev, struct winluid vgpu_luid =3D {}; struct dxgk_vmbus_guestcaps guest_caps =3D {.wsl2 =3D 1}; struct dxgglobal *dxgglobal =3D dxggbl(); + struct dxgk_vmbus_hostcaps host_caps =3D {}; =20 mutex_lock(&dxgglobal->device_mutex); =20 @@ -503,6 +525,13 @@ static int dxg_pci_probe_device(struct pci_dev *dev, if (ret) goto cleanup; =20 + ret =3D pci_read_config_dword(dev, DXGK_VMBUS_HOSTCAPS_OFFSET, + &host_caps.host_caps); + if (ret =3D=3D 0) { + if (host_caps.map_guest_memory) + dxgglobal->map_guest_pages_enabled =3D true; + } + if (dxgglobal->vmbus_ver > DXGK_VMBUS_INTERFACE_VERSION) dxgglobal->vmbus_ver =3D DXGK_VMBUS_INTERFACE_VERSION; } diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 425a1ab87bd6..4d7807909284 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1383,15 +1383,19 @@ int create_existing_sysmem(struct dxgdevice *device, void *kmem =3D NULL; int ret =3D 0; struct dxgkvmb_command_setexistingsysmemstore *set_store_command; + struct dxgkvmb_command_setexistingsysmempages *set_pages_command; u64 alloc_size =3D host_alloc->allocation_size; u32 npages =3D alloc_size >> PAGE_SHIFT; struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; - - ret =3D init_message(&msg, device->adapter, device->process, - sizeof(*set_store_command)); - if (ret) - goto cleanup; - set_store_command =3D (void *)msg.msg; + const u32 max_pfns_in_message =3D + (DXG_MAX_VM_BUS_PACKET_SIZE - sizeof(*set_pages_command) - + PAGE_SIZE) / sizeof(__u64); + u32 alloc_offset_in_pages =3D 0; + struct page **page_in; + u64 *pfn; + u32 pages_to_send; + u32 i; + struct dxgglobal *dxgglobal =3D dxggbl(); =20 /* * Create a guest physical address list and set it as the allocation @@ -1402,6 +1406,7 @@ int create_existing_sysmem(struct dxgdevice *device, DXG_TRACE("Alloc size: %lld", alloc_size); =20 dxgalloc->cpu_address =3D (void *)sysmem; + dxgalloc->pages =3D vzalloc(npages * sizeof(void *)); if (dxgalloc->pages =3D=3D NULL) { DXG_ERR("failed to allocate pages"); @@ -1419,39 +1424,87 @@ int create_existing_sysmem(struct dxgdevice *device, ret =3D -ENOMEM; goto cleanup; } - kmem =3D vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL); - if (kmem =3D=3D NULL) { - DXG_ERR("vmap failed"); - ret =3D -ENOMEM; - goto cleanup; - } - ret1 =3D vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem, - alloc_size, &dxgalloc->gpadl); - if (ret1) { - DXG_ERR("establish_gpadl failed: %d", ret1); - ret =3D -ENOMEM; - goto cleanup; - } + if (!dxgglobal->map_guest_pages_enabled) { + ret =3D init_message(&msg, device->adapter, device->process, + sizeof(*set_store_command)); + if (ret) + goto cleanup; + set_store_command =3D (void *)msg.msg; + + kmem =3D vmap(dxgalloc->pages, npages, VM_MAP, PAGE_KERNEL); + if (kmem =3D=3D NULL) { + DXG_ERR("vmap failed"); + ret =3D -ENOMEM; + goto cleanup; + } + ret1 =3D vmbus_establish_gpadl(dxgglobal_get_vmbus(), kmem, + alloc_size, &dxgalloc->gpadl); + if (ret1) { + DXG_ERR("establish_gpadl failed: %d", ret1); + ret =3D -ENOMEM; + goto cleanup; + } #ifdef _MAIN_KERNEL_ - DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle); + DXG_TRACE("New gpadl %d", dxgalloc->gpadl.gpadl_handle); #else - DXG_TRACE("New gpadl %d", dxgalloc->gpadl); + DXG_TRACE("New gpadl %d", dxgalloc->gpadl); #endif =20 - command_vgpu_to_host_init2(&set_store_command->hdr, - DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE, - device->process->host_handle); - set_store_command->device =3D device->handle; - set_store_command->device =3D device->handle; - set_store_command->allocation =3D host_alloc->allocation; + command_vgpu_to_host_init2(&set_store_command->hdr, + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMSTORE, + device->process->host_handle); + set_store_command->device =3D device->handle; + set_store_command->allocation =3D host_alloc->allocation; #ifdef _MAIN_KERNEL_ - set_store_command->gpadl =3D dxgalloc->gpadl.gpadl_handle; + set_store_command->gpadl =3D dxgalloc->gpadl.gpadl_handle; #else - set_store_command->gpadl =3D dxgalloc->gpadl; + set_store_command->gpadl =3D dxgalloc->gpadl; #endif - ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, msg.size); - if (ret < 0) - DXG_ERR("failed to set existing store: %x", ret); + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, msg.hdr, + msg.size); + if (ret < 0) + DXG_ERR("failed set existing store: %x", ret); + } else { + /* + * Send the list of the allocation PFNs to the host. The host + * will map the pages for GPU access. + */ + + ret =3D init_message(&msg, device->adapter, device->process, + sizeof(*set_pages_command) + + max_pfns_in_message * sizeof(u64)); + if (ret) + goto cleanup; + set_pages_command =3D (void *)msg.msg; + command_vgpu_to_host_init2(&set_pages_command->hdr, + DXGK_VMBCOMMAND_SETEXISTINGSYSMEMPAGES, + device->process->host_handle); + set_pages_command->device =3D device->handle; + set_pages_command->allocation =3D host_alloc->allocation; + + page_in =3D dxgalloc->pages; + while (alloc_offset_in_pages < npages) { + pfn =3D (u64 *)((char *)msg.msg + + sizeof(*set_pages_command)); + pages_to_send =3D min(npages - alloc_offset_in_pages, + max_pfns_in_message); + set_pages_command->num_pages =3D pages_to_send; + set_pages_command->alloc_offset_in_pages =3D + alloc_offset_in_pages; + + for (i =3D 0; i < pages_to_send; i++) + *pfn++ =3D page_to_pfn(*page_in++); + + ret =3D dxgvmb_send_sync_msg_ntstatus(msg.channel, + msg.hdr, + msg.size); + if (ret < 0) { + DXG_ERR("failed set existing pages: %x", ret); + break; + } + alloc_offset_in_pages +=3D pages_to_send; + } + } =20 cleanup: if (kmem) diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index 88967ff6a505..b4a98f7c2522 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -234,6 +234,16 @@ struct dxgkvmb_command_setexistingsysmemstore { u32 gpadl; }; =20 +/* 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; diff --git a/drivers/hv/dxgkrnl/misc.c b/drivers/hv/dxgkrnl/misc.c index cb1e0635bebc..4a1309d80ee5 100644 --- a/drivers/hv/dxgkrnl/misc.c +++ b/drivers/hv/dxgkrnl/misc.c @@ -35,3 +35,4 @@ u16 *wcsncpy(u16 *dest, const u16 *src, size_t n) dest[i - 1] =3D 0; return dest; } +