From nobody Mon Apr 6 10:42:02 2026 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (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 A29043FA5E0 for ; Thu, 19 Mar 2026 20:25:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951944; cv=none; b=IK1ZRYFbtfr6oiK1lyYMuJ27G6UlL9h6M1u6D1oo4cT2iCrFlW0bM2jCAPoW035Rvc8q2/N80aQ9lK/Hp45Luut2Pr/Ut8+rrIzVAfptsaGqU8bKsWtNyPop7cH5EMUAujzyNXqcrDmEC/HwBROPm5uZN1aTVbwgF3IhgSMKB9Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773951944; c=relaxed/simple; bh=S8QKX0NZSQwSO6HdzqOHD5S8SMoE062+vSMVmXGkj2U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=f8bAeQEOzsoxFTEMWZyjB71IB/H+T8RdqEYtxYIe+ftuWIx253YAW7jR3BoB6qdeoo7YzSR1/5OtMQ9iu8EIUPU8DL7kzjG3Msm5TJNXdUPBrsAq1fjbukA3tm+om4SwLpb7V5IxofJg+qlyQwindO/h2IYjg/Wrk/41QNMiXQI= 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=IPsAoz0A; arc=none smtp.client-ip=209.85.221.43 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="IPsAoz0A" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-439b9cf8cb5so1714761f8f.0 for ; Thu, 19 Mar 2026 13:25:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773951938; x=1774556738; 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=qrH2a5k/EhZDhIUyy4Q/uQ6n7kgRZKjSjI2+9Ckr7IY=; b=IPsAoz0AVJrPIESWw78xjrgdsEUq+Ch0E9HQAnupYtWJzSeL5HmXdmSBs6BbKUHR2w +Y9Bh9WEpkXlpA1Ot3RcMyYOQt49ulAbs4rufJ4QcQ1WA1YPev2YEzqWoBxw/c5/E7gi ZMD39FPb3r4wRIUoQFUti197OU6wEbUZFZ6hRrec1ju/QhdQ12LRlSsHea+iORAdhXxW ILkxL2meMWzWHNhwcOn8Au2sGxgEKSNYEoC9x4XIOlAy33ZcoacnQ8iYX8gCtGsZ5gT0 GReYFGStdcJtuq6PuEesnDB1Zj5WnTLypmcvxxE461B/g76oLK0BdQuk/ZUyH+p5nZoK +jTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773951938; x=1774556738; 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=qrH2a5k/EhZDhIUyy4Q/uQ6n7kgRZKjSjI2+9Ckr7IY=; b=rhQd95JmtoGvuUzvNnl8e2gtoR8FAtl73vpLXuGObJDa83YFylkMJJMGu329XHjUC7 aAr0HoypYOST+vGoMsIacQS5KaxeVYFopj6EvYx/M6onwfqOBDlJYBPrjG6XksCZyS8n jh6XcwyeQARC9WrEyaTPW9lAXYe/3qA5T7lJ02MgEx2EhkSC5Azz+cxamuxzKtaRRNmg PB24HARg/Rjuau8kMZm01h23Fk19JggTszVS9ioHCaMZ065f0VwRZM2WlNf0C0SYrDim dNd2rXh0LJtaa0Un+1AaMQeMeD2CpCiw2eIoZ0y+xs2CWxFeqCr9nLYdstxLKvu6npGA 4huw== X-Gm-Message-State: AOJu0Yxmp3q11O4FIu2yZf/iWCsqvuMJ1IYj1+Sm9bw6eGN9QtW6zhoP 4RMUruLCpnyD9laJAapDOmiZXoD5FntCDQhG/uiea1hoGHqvkzF8EHqA X-Gm-Gg: ATEYQzxHtZH0xZhoWvSPiYhfBcb/pVZ8p8U1j9Y+2sRzw9//MT7x0+7sxR3tVvcVUMZ DHZpD/d9StTc4ZFsDk/5GSAn8FrSGRoIW0VDFsq8PWEaC0r5m3/SP+4FO99LRgaIB288f8hKPSa AFe0tDC/k8GYF3WJ7Qk2mJvF0GimBa4uv09IYYX1uJY87A+1XYq2GZsrrE8Gq7v6jaJmR84yIem RPTzaUVJ93KolsDw0eDOjIWxJ0mWT9NxOVkFliVm3h+sxVXN5WLFk5FEGlRpTBdnVlWprz69UkR RdJnCQo+ZKEVbFPSSf2OYoeQWrrP6qnxs75+11scVOtovF0xXjJZBxA85mKEqv5Vk7/kizyn6aa fmfxZfUGKZbbc2AY5acE9vp9ffVnc9HS0Z5JVabRhBUEhTIyGuO92Ms11ALl/opWQj8VPJCR2Zc vD3zNvx885fUUWLb7aAc6+BgbO8NA4p43Z/52R4iVrAM9Ly3Ie X-Received: by 2002:a05:6000:2089:b0:43b:5356:a7fc with SMTP id ffacd0b85a97d-43b6428b374mr1145476f8f.55.1773951937820; Thu, 19 Mar 2026 13:25:37 -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.36 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 19 Mar 2026 13:25:37 -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 21/55] drivers: hv: dxgkrnl: The escape ioctl Date: Thu, 19 Mar 2026 20:24:35 +0000 Message-ID: <20260319202509.63802-22-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 the escape ioctl (LX_DXESCAPE). This ioctl is used to send/receive private data between user mode compute device driver (guest) and kernel mode compute device driver (host). It allows the user mode driver to extend the virtual compute device API. 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/dxgkrnl.h | 3 ++ drivers/hv/dxgkrnl/dxgvmbus.c | 75 ++++++++++++++++++++++++++++++++--- drivers/hv/dxgkrnl/dxgvmbus.h | 12 ++++++ drivers/hv/dxgkrnl/ioctl.c | 42 +++++++++++++++++++- include/uapi/misc/d3dkmthk.h | 41 +++++++++++++++++++ 5 files changed, 167 insertions(+), 6 deletions(-) diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h index b6a7288a4177..dafc721ed6cf 100644 --- a/drivers/hv/dxgkrnl/dxgkrnl.h +++ b/drivers/hv/dxgkrnl/dxgkrnl.h @@ -894,6 +894,9 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess= *process, struct dxgadapter *adapter, struct d3dkmt_queryallocationresidency *args); +int dxgvmb_send_escape(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_escape *args); int dxgvmb_send_query_vidmem_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryvideomemoryinfo *args, diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c index 48ff49456057..8bdd49bc7aa6 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.c +++ b/drivers/hv/dxgkrnl/dxgvmbus.c @@ -1925,6 +1925,70 @@ int dxgvmb_send_query_alloc_residency(struct dxgproc= ess *process, return ret; } =20 +int dxgvmb_send_escape(struct dxgprocess *process, + struct dxgadapter *adapter, + struct d3dkmt_escape *args) +{ + int ret; + struct dxgkvmb_command_escape *command =3D NULL; + u32 cmd_size =3D sizeof(*command); + struct dxgvmbusmsg msg =3D {.hdr =3D NULL}; + + if (args->priv_drv_data_size > DXG_MAX_VM_BUS_PACKET_SIZE) { + ret =3D -EINVAL; + goto cleanup; + } + + cmd_size =3D cmd_size - sizeof(args->priv_drv_data[0]) + + args->priv_drv_data_size; + + ret =3D init_message(&msg, adapter, process, cmd_size); + if (ret) + goto cleanup; + command =3D (void *)msg.msg; + command_vgpu_to_host_init2(&command->hdr, + DXGK_VMBCOMMAND_ESCAPE, + process->host_handle); + command->adapter =3D args->adapter; + command->device =3D args->device; + command->type =3D args->type; + command->flags =3D args->flags; + command->priv_drv_data_size =3D args->priv_drv_data_size; + command->context =3D args->context; + if (args->priv_drv_data_size) { + ret =3D copy_from_user(command->priv_drv_data, + args->priv_drv_data, + args->priv_drv_data_size); + if (ret) { + DXG_ERR("failed to copy priv data"); + ret =3D -EINVAL; + goto cleanup; + } + } + + ret =3D dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size, + command->priv_drv_data, + args->priv_drv_data_size); + if (ret < 0) + goto cleanup; + + if (args->priv_drv_data_size) { + ret =3D copy_to_user(args->priv_drv_data, + command->priv_drv_data, + args->priv_drv_data_size); + if (ret) { + DXG_ERR("failed to copy priv data"); + ret =3D -EINVAL; + } + } + +cleanup: + free_message(&msg, process); + if (ret) + DXG_TRACE("err: %d", ret); + return ret; +} + int dxgvmb_send_query_vidmem_info(struct dxgprocess *process, struct dxgadapter *adapter, struct d3dkmt_queryvideomemoryinfo *args, @@ -1955,14 +2019,14 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess= *process, ret =3D copy_to_user(&output->budget, &result.budget, sizeof(output->budget)); if (ret) { - pr_err("%s failed to copy budget", __func__); + DXG_ERR("failed to copy budget"); ret =3D -EINVAL; goto cleanup; } ret =3D copy_to_user(&output->current_usage, &result.current_usage, sizeof(output->current_usage)); if (ret) { - pr_err("%s failed to copy current usage", __func__); + DXG_ERR("failed to copy current usage"); ret =3D -EINVAL; goto cleanup; } @@ -1970,7 +2034,7 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess *= process, &result.current_reservation, sizeof(output->current_reservation)); if (ret) { - pr_err("%s failed to copy reservation", __func__); + DXG_ERR("failed to copy reservation"); ret =3D -EINVAL; goto cleanup; } @@ -1978,14 +2042,14 @@ int dxgvmb_send_query_vidmem_info(struct dxgprocess= *process, &result.available_for_reservation, sizeof(output->available_for_reservation)); if (ret) { - pr_err("%s failed to copy avail reservation", __func__); + DXG_ERR("failed to copy avail reservation"); ret =3D -EINVAL; } =20 cleanup: free_message(&msg, process); if (ret) - dev_dbg(DXGDEV, "err: %d", ret); + DXG_TRACE("err: %d", ret); return ret; } =20 @@ -3152,3 +3216,4 @@ int dxgvmb_send_submit_command_hwqueue(struct dxgproc= ess *process, DXG_TRACE("err: %d", ret); return ret; } + diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h index a1549983d50f..e1c2ed7b1580 100644 --- a/drivers/hv/dxgkrnl/dxgvmbus.h +++ b/drivers/hv/dxgkrnl/dxgvmbus.h @@ -664,6 +664,18 @@ struct dxgkvmb_command_queryallocationresidency_return= { /* d3dkmt_allocationresidencystatus[NumAllocations] */ }; =20 +/* Returns only private data */ +struct dxgkvmb_command_escape { + struct dxgkvmb_command_vgpu_to_host hdr; + struct d3dkmthandle adapter; + struct d3dkmthandle device; + enum d3dkmt_escapetype type; + struct d3dddi_escapeflags flags; + u32 priv_drv_data_size; + struct d3dkmthandle context; + u8 priv_drv_data[1]; +}; + struct dxgkvmb_command_queryvideomemoryinfo { struct dxgkvmb_command_vgpu_to_host hdr; struct d3dkmthandle adapter; diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c index e692b127e219..78de76abce2d 100644 --- a/drivers/hv/dxgkrnl/ioctl.c +++ b/drivers/hv/dxgkrnl/ioctl.c @@ -3547,6 +3547,46 @@ dxgkio_flush_heap_transitions(struct dxgprocess *pro= cess, void *__user inargs) return ret; } =20 +static int +dxgkio_escape(struct dxgprocess *process, void *__user inargs) +{ + struct d3dkmt_escape args; + int ret; + struct dxgadapter *adapter =3D NULL; + bool adapter_locked =3D false; + + ret =3D copy_from_user(&args, inargs, sizeof(args)); + if (ret) { + ret =3D -EINVAL; + goto cleanup; + } + + adapter =3D dxgprocess_adapter_by_handle(process, args.adapter); + if (adapter =3D=3D NULL) { + ret =3D -EINVAL; + goto cleanup; + } + + ret =3D dxgadapter_acquire_lock_shared(adapter); + if (ret < 0) { + adapter =3D NULL; + goto cleanup; + } + adapter_locked =3D true; + + args.adapter =3D adapter->host_handle; + ret =3D dxgvmb_send_escape(process, adapter, &args); + +cleanup: + + if (adapter_locked) + dxgadapter_release_lock_shared(adapter); + if (adapter) + kref_put(&adapter->adapter_kref, dxgadapter_release); + DXG_TRACE("ioctl:%s %d", errorstr(ret), ret); + return ret; +} + static int dxgkio_query_vidmem_info(struct dxgprocess *process, void *__user inargs) { @@ -4338,7 +4378,7 @@ static struct ioctl_desc ioctls[] =3D { /* 0x0a */ {dxgkio_query_vidmem_info, LX_DXQUERYVIDEOMEMORYINFO}, /* 0x0b */ {}, /* 0x0c */ {}, -/* 0x0d */ {}, +/* 0x0d */ {dxgkio_escape, LX_DXESCAPE}, /* 0x0e */ {dxgkio_get_device_state, LX_DXGETDEVICESTATE}, /* 0x0f */ {dxgkio_submit_command, LX_DXSUBMITCOMMAND}, /* 0x10 */ {dxgkio_create_sync_object, LX_DXCREATESYNCHRONIZATIONOBJECT}, diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h index b7d8b1d91cfc..749edf28bd43 100644 --- a/include/uapi/misc/d3dkmthk.h +++ b/include/uapi/misc/d3dkmthk.h @@ -236,6 +236,45 @@ struct d3dddi_destroypagingqueue { struct d3dkmthandle paging_queue; }; =20 +enum d3dkmt_escapetype { + _D3DKMT_ESCAPE_DRIVERPRIVATE =3D 0, + _D3DKMT_ESCAPE_VIDMM =3D 1, + _D3DKMT_ESCAPE_VIDSCH =3D 3, + _D3DKMT_ESCAPE_DEVICE =3D 4, + _D3DKMT_ESCAPE_DRT_TEST =3D 8, +}; + +struct d3dddi_escapeflags { + union { + struct { + __u32 hardware_access:1; + __u32 device_status_query:1; + __u32 change_frame_latency:1; + __u32 no_adapter_synchronization:1; + __u32 reserved:1; + __u32 virtual_machine_data:1; + __u32 driver_known_escape:1; + __u32 driver_common_escape:1; + __u32 reserved2:24; + }; + __u32 value; + }; +}; + +struct d3dkmt_escape { + struct d3dkmthandle adapter; + struct d3dkmthandle device; + enum d3dkmt_escapetype type; + struct d3dddi_escapeflags flags; +#ifdef __KERNEL__ + void *priv_drv_data; +#else + __u64 priv_drv_data; +#endif + __u32 priv_drv_data_size; + struct d3dkmthandle context; +}; + enum dxgk_render_pipeline_stage { _DXGK_RENDER_PIPELINE_STAGE_UNKNOWN =3D 0, _DXGK_RENDER_PIPELINE_STAGE_INPUT_ASSEMBLER =3D 1, @@ -1217,6 +1256,8 @@ struct d3dkmt_shareobjectwithhost { _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo) #define LX_DXQUERYVIDEOMEMORYINFO \ _IOWR(0x47, 0x0a, struct d3dkmt_queryvideomemoryinfo) +#define LX_DXESCAPE \ + _IOWR(0x47, 0x0d, struct d3dkmt_escape) #define LX_DXGETDEVICESTATE \ _IOWR(0x47, 0x0e, struct d3dkmt_getdevicestate) #define LX_DXSUBMITCOMMAND \