From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48D4548094C; Fri, 14 Aug 2026 15:29:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721376; cv=none; b=JcKMebLM3ihc8A7qHvc10uko1M3v6CHdTfW7qdNNFHL+vX5wMx5uWgbOPs2WZpdJ+HGRWAWj9xt/VBsrYYmt4HFcJjxTpt740NZ9yHywiNUWWsiDk7yfEmUUgUHWw6qFY4qTV2mUMsJLxvDGkK1ONQrdAcesoaJBr0ejNaV0Z9c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721376; c=relaxed/simple; bh=ScjQCmJqu66W5maE8eMUSbpYSWVqT/TO89ycN7X6uU4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=u7+Bt13UsmwakuNlVDsU+/l4SZobraf8dcml9G9OH26vLY9om4jqQZl8fGDStwZSbjVP6pLexkFJxAyLuEETxZ49mddW9LEZgelHgttCkepxpgo6IswSbH7mSw7zTsGGOwyCu5N2L3vQmOaSfsbUWEa87ccVeufq3CZkW0TnSXM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mykojCV4; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mykojCV4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 30CD91F000E9; Fri, 14 Aug 2026 15:29:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721374; bh=Y3WFbhYTWczQCYOlTAjPPPmhWM8d8ALyu3lGu1XHIBs=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=mykojCV41BnK/iJkPAguTL+RI2wDcQ1SD57YdKrUElibS4WSpDNQkBu8Lq6XGqMbH AJEDxQph7N0tUO1yZKMiCqSkemF85r/GGhbMYxb0aeE+KRQd39TMD9b+kvsRrnz5xt wKVJJaw8q6uX7xDp72PX21wYNvfErAR+O7dnDZ0OzAvuduZej9lnyatPlhJMF7U4gC B1RkD6dcmZTYgozHExhKtztI0OcvpGQ6vhBJbdhDZcNfLPR7II0LriCf4+DMxM4CrA qCECaLtdACBr6des5w3hCzwX8rPpHd1NgRUBGOKxQb9pPsAYLVzLCFrLcuijXBlTVg AXkAO1+ePa80Q== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:09 +0200 Subject: [PATCH v5 01/10] dt-bindings: reserved-memory: Document Tegra VPR Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-1-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3632; i=treding@nvidia.com; h=from:subject:message-id; bh=lz5bdbUU9mR9/O2pGRVuSC+tGOj+4+d05JhFJg7QQcs=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRX2YHaMFl/MMqaO8DjWshO3BEhug3DR5p3N KvPnok5eVqJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80VwAKCRDdI6zXfz6z oaazD/9psLx3MYjiBHriTuCoCIMM1/M4o4m1z3kY244q0OcagkN7WBcGKQQ8sh9qS9yPn+Wjokz lPnheeraE3S0jAjAs12Zaiqx68oWR3MPgzvELGc2Z5VDTmJKqBr/F4Rmy0fm6ImK3qS65Vdlkj9 bTUd0elQ/+r1HMLfr0oQ9BRmq3LZ0L8ImlxOi929w5MzmELWrBp0TRsZSKcAj3t+CCEjPNpZkmH vSbyTz45epBGMEj8c243jPDCR8d40cQIGVy5aYb4Y1YTCIYEE2ih8UXQyvQTsuVHjEgtrB5tL6U Vxej6hfNTpYF1PUPWLZglt5aFbzaEqT/nyyCOYkCcrRKJq0Xi94XiEFr/sbYonwhYl85aG4jQ7m qoI9ScD34a2bjl+Ixnw7MsYZ7OARaXx53Ha29EDXM5r1P9s/EnQt7G/8Z4f/W1J1so7t4gQIuHK +J2bwazXCktsA1nG7wAsar1Cd6sQLebYKyqMKTvriFCxJUtJANWRhK1b96ytMINjHhxmibC3la8 sSoFz2U45tFAt4BRLb0Yt+ZFOiXZBWemw+goe5l0uVCzkhCy+omPYPq8/35qiVRxl3OSYmA9RFE ZqKrsbrgwA6H6ASFWqT1cGW9trxnTVdQJt+oMnGqCpNb9XvLPFqTfxXw+SnkIar0ykHOLxHPdt/ mwZmJ2pCIKIoSzw== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding The Video Protection Region (VPR) found on NVIDIA Tegra chips is a region of memory that is protected from CPU accesses. It is used to decode and play back DRM protected content. It is a standard reserved memory region that can exist in two forms: static VPR where the base address and size are fixed (uses the "reg" property to describe the memory) and a resizable VPR where only the size is known upfront and the OS can allocate it wherever it can be accomodated. Reviewed-by: Rob Herring (Arm) Signed-off-by: Thierry Reding --- Changes in v4: - move oneOf into allOf for a bit more tidiness - fix example "reg" property Changes in v3: - add examples for fixed and resizable VPR --- .../nvidia,tegra-video-protection-region.yaml | 75 ++++++++++++++++++= ++++ 1 file changed, 75 insertions(+) diff --git a/Documentation/devicetree/bindings/reserved-memory/nvidia,tegra= -video-protection-region.yaml b/Documentation/devicetree/bindings/reserved-= memory/nvidia,tegra-video-protection-region.yaml new file mode 100644 index 000000000000..862bfd391378 --- /dev/null +++ b/Documentation/devicetree/bindings/reserved-memory/nvidia,tegra-video-= protection-region.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reserved-memory/nvidia,tegra-video-prot= ection-region.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra Video Protection Region (VPR) + +maintainers: + - Thierry Reding + - Jon Hunter + +description: | + NVIDIA Tegra chips have long supported a mechanism to protect a single, + contiguous memory region from non-secure memory accesses. Typically this + region is used for decoding and playback of DRM protected content. Vario= us + devices, such as the display controller and multimedia engines (video + decoder) can access this region in a secure way. Access from the CPU is + generally forbidden. + + Two variants exist for VPR: one is fixed in both the base address and si= ze, + while the other is resizable. Fixed VPR can be described by just a "reg" + property specifying the base address and size, whereas the resizable VPR + is defined by a size/alignment pair of properties. For resizable VPR the + memory is reusable by the rest of the system when it's unused for VPR and + therefore the "reusable" property must be specified along with it. For a + fixed VPR, the memory is permanently protected, and therefore it's not + reusable and must also be marked as "no-map" to prevent any (including + speculative) accesses to it. + +allOf: + - $ref: reserved-memory.yaml + - oneOf: + - required: + - compatible + - reg + + - required: + - compatible + - size + +properties: + compatible: + const: nvidia,tegra-video-protection-region + +dependencies: + size: [alignment, reusable] + alignment: [size, reusable] + reusable: [alignment, size] + + reg: [no-map] + no-map: [reg] + +unevaluatedProperties: false + +examples: + - | + /* resizable VPR */ + protected { + compatible =3D "nvidia,tegra-video-protection-region"; + + size =3D <0x0 0x70000000>; + alignment =3D <0x0 0x100000>; + reusable; + }; + + - | + /* fixed VPR */ + protected@a8000000 { + compatible =3D "nvidia,tegra-video-protection-region"; + + /* fixed VPR */ + reg =3D <0xa8000000 0x70000000>; + no-map; + }; --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1148F47DFB0; Fri, 14 Aug 2026 15:29:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721379; cv=none; b=hytQv9qGqZFUpOLm1DW0xfuXKP3/aGrUHERdYNcck2kHNkm8Nhm1aY1T6cZ+fytxWmUqb1nIihkutI14pXin2TkD4AZD2RAqnzCQJQEt4Q/YA4UKkDRkWCvbxB0h3VnnomNzQEwPSZE9gq1Rto6NuWs+aBSAM9dVjv4JnGUXBtk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721379; c=relaxed/simple; bh=KZt42RcI2xZOV6ZL4xNzHGcUviEo1o5J+l+Mdce427o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZG896zWZbODJRzl8kC85T83IlJEpBzVBdT0aTxIVNFWjwiRJHnj8kv4XCECSPfJyqPqmeW+BTuqZhJFgUjwzosOAU7I0kELiX4PCRKrjzaS646RzvB+HdTu79Aq8uJOyhBOQ/gBUumRgFoaEU7/K2tbC8EchY5GO5nh1mt4DS40= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SQYinDf8; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SQYinDf8" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 026D31F00A3A; Fri, 14 Aug 2026 15:29:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721377; bh=eBlEuAoqOked/LKJu9mRAOEywcTF2CIu7f/dTPjyTCg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=SQYinDf84Qyd8J39yvDDkE+2yMa0qkyakiGRRmXf/fx0fg4kEyB3/sFc3snNGwS4a gZYSriilhL0IMm0YA0eTk+Fr6+tib5AjGC+psqwuOr58cPmjYAIuQzHxP0Ge6jse5c SYvbKj5F6GHpZyOthwjNwOz8ZbWANjEirhoY4Es1XYu7sKTCZsKE/pVkWklj/YJyCn 1Kxbk35QjJ2mW8iRQFaDdfUyLz4khPYq4BpXf8zT3m4sYZxyiEfY2ONGzN2rFEwQDd 9zml7Ja1+KceKUU1i9huNizcSLqzefA6V4HsIplKC9KeQgA7MEOtO96w4DwQS+9MES DZXezd2+lIsYw== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:10 +0200 Subject: [PATCH v5 02/10] dt-bindings: display: tegra: Document memory regions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-2-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3649; i=treding@nvidia.com; h=from:subject:message-id; bh=pBYGfO+OoRCfoGlySA1v5aSrpzUlJ6EhDp5j2u2Nips=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRXaRTeDiDu4YBKZoD7GNeMdeApLEEF/47+P Qs7Dg4EFyCJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80VwAKCRDdI6zXfz6z oUKBEACxEJAOL5zdS5PgXCqYYzzNGiLLXVhgFzk9U1eqr3vc0dKYuq2vq77WgkFBI5rq7KrvFNH 9h3HArdCO4FtE5FqV3SMFXSGQgi45SAZ/XdBjP1goIG38+OdMbFWNyaOl9YPEvNDN1Yn7P9Xjvg VrX6hTODGnRwC3W6pjviCz9yboRmRInlgIzCKkXCwYKMoH0Jru+o0ghVJ+EEuVUjG+92JbtTYRf ISKuI3IJKNrZBVSEG7TmHBxpAbWMvPLrFyPR5GV1L8sQL/eR3VjObNlgyJ6fCXo66ArRvJXUoIn 5JE4la8W3ApL+k4SCDAA9iSSdm5qpPhWD+xbbh5q57FsGCQliDaDBGt3j0iwRWrh5vboKT8Vy2L iCnF1QDKpvsQgkZKor/kBAT0A+cS9EEvqyaPiVfnPr9MV4DM7rZLblI8afcRz+AlbF+SPprte76 InWAWIl0Y+51c4Sy6SDRSNjQfRxRTmP5DjmykikMD6ItCdY2igse1frokTOU9npaT0QZcLbuRiy qEu5R3XiC+4VApabAOIRvpF2wKDaaBhtaUZuXb9C8A6fslgF/VvQUMsiI9R2P7+w3B5kxhUYgpa rqyzS0AgP0wdt22bH0ObJuoXXTtOjm/ualj5F/PXaPsdAmBCavu2SzT89QueATL3Xdx8JV9IzeN l2c2CdbqjX3XlyQ== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding Add the memory-region and memory-region-names properties to the bindings for the display controllers and the host1x engine found on various Tegra generations. These memory regions are used to access firmware-provided framebuffer memory as well as the video protection region. Reviewed-by: Rob Herring (Arm) Signed-off-by: Thierry Reding --- Changes in v4: - typofix Changes in v3: - document properties for VIC --- .../devicetree/bindings/display/tegra/nvidia,tegra124-vic.yaml | 8 ++++++= ++ .../devicetree/bindings/display/tegra/nvidia,tegra186-dc.yaml | 10 ++++++= ++++ .../devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml | 10 ++++++= +++- .../bindings/display/tegra/nvidia,tegra20-host1x.yaml | 7 +++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra12= 4-vic.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra12= 4-vic.yaml index bdf981781bd5..fdd3fe9e2547 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra124-vic.y= aml +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra124-vic.y= aml @@ -68,6 +68,14 @@ properties: - const: dma-mem # read - const: write =20 + memory-region: + items: + - description: reference to the video protection memory region + + memory-region-names: + items: + - const: protected + dma-coherent: true =20 additionalProperties: false diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra18= 6-dc.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra186= -dc.yaml index ce4589466a18..881bfbf4764d 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra186-dc.ya= ml +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra186-dc.ya= ml @@ -57,6 +57,16 @@ properties: - const: dma-mem # read-0 - const: read-1 =20 + memory-region: + minItems: 1 + maxItems: 2 + + memory-region-names: + items: + enum: [ framebuffer, protected ] + minItems: 1 + maxItems: 2 + nvidia,outputs: description: A list of phandles of outputs that this display controller can drive. diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20= -dc.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-d= c.yaml index 69be95afd562..3bf06dcd6198 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml @@ -65,7 +65,15 @@ properties: items: - description: phandle to the core power domain =20 - memory-region: true + memory-region: + minItems: 1 + maxItems: 2 + + memory-region-names: + items: + enum: [ framebuffer, protected ] + minItems: 1 + maxItems: 2 =20 nvidia,head: $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20= -host1x.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra= 20-host1x.yaml index 8312b7699cbe..420a1fe5ee80 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x= .yaml +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x= .yaml @@ -98,6 +98,13 @@ properties: items: - description: phandle to the HEG or core power domain =20 + memory-region: + maxItems: 1 + + memory-region-names: + items: + - const: protected + required: - compatible - interrupts --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE89148124F; Fri, 14 Aug 2026 15:29:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721384; cv=none; b=cFwZWO0J3rvZ37SM7yWmv+6QjcDvYJeAlbulOJjwSKPJ9hYpFqs9e53tK2NPWEh9ED3NAOBi0jELQqkoJf+IRq/GZOrfWrkNg8UL1FqpUutAoo262WXcP41d75YFnGcRe7Mga8Gnj1xMXkvXV5cqQnY7/pEITcQq1h0zxEPuEGA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721384; c=relaxed/simple; bh=D4Xh9zc5N/4RWPWjcg0XK0nxc0XsnOaquGDBNqbZDwM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZLBd1J5gunPcBCmaCJDJyNoJ+7Yow28uTsutIRsL5gNTxjiPcdN0w9nMV+IYHe8+OcmPYlGZ/vccoyeNMnW3s0AVbjpCiW06BbckDysZJo5QBv5V9QmQl3NQXxejxrhgSP3S0rQXqy9XH8k8SbwJ+nW4wuZDIYpOJMXdTPgV8Po= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=flinAHY2; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="flinAHY2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C6F381F000E9; Fri, 14 Aug 2026 15:29:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721380; bh=hagYf35q6G2UhsHzty44d2izTZaC/NeM9Zitkk0WHRQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=flinAHY2TCzAQp51/VofbBun1xlQT2bmsz0G1F/e/noxEOuSLeCum+o7maLYlpqmQ /fCNRK5u2pVUDff9WOpgjdwfv0VumaETvgyjBD4m7+9abjd9YoLuS7S3vH2wdng+V6 uj7WjDBEYfLKM0HpZIxqjl1aAMkhgGMzLDS8HyEPqzQENhaojB43Nb+uGZYwrR+2S9 AmOQ7kiZ37CH0EhkOYKjVh1rHWwCiz9CFNYIp+EQLcshpuHC8XmP2t6KaIqriIeuuk 1mU79Rz9lLEOUmvrPQziSTmt4Y/uAz4fcbHpt43cs5nOKiBPHM6LWTWen7lsSUWhav YJb4sUfspUFpw== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:11 +0200 Subject: [PATCH v5 03/10] dt-bindings: gpu: host1x: Document memory-regions for NVDEC Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-3-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1123; i=treding@nvidia.com; h=from:subject:message-id; bh=96od8SnVSYMiavrRwbh7Ehk1YxWlsQuy9Uk4ZKu5YoI=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRXzzaJcNN7yh/4w8KOcdpo2zu6d8W+euiDX mBrAATLPxSJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80VwAKCRDdI6zXfz6z oTw8EACuc0eBM13PSAlDb5GHdm6QtW4MAiTJa1Pw+FwiKHMIRJpmpzbu0iIG0ZOdmChmnu2ClwP s3gbqJ6YRrL9ruy46tyMj0RVjZmP+8itbMFX9Dzx1WQ20c6wSYZPljF4/NT2DncBSidJT9msAw/ Isipo/ka6MqadTIpfMi+veITAsnb1pJn0wugYxr/lecYT1Qqk8pwaBDtrh6QcceAiyT4XfUkuG/ V6wZv8UbLps/2wgNoUPKoxF2rAqYsH4936MxwWMKbqK9HdO39ObjyAvfkRyBoSyITu9IEC+Tvz7 VGGB576u4oSzVEUSJCQfgVFE1uvf4l1aOpmgYgzzp4PRcRg8nuu6eyjSjJ1TtNl+zU8SU6uthvC zv49vGosmKrQ385BX94aSlQ356vW9xuaN96c66oAzrSwDFpyXthbnEQLJoOBaKQVQFbaQMfvGwX CgTQD4FXkcZnm85qZr6J0K8TKMtlY/NPvtDpB9kMN93B/PVT5GASAQI2wE9uKDq1Tq30K+I68c3 zO9oJ9WO09izzerU9CXmI42KivHR3h5CUiTV4O0eeAE+LvA7T/kgD2XTTur3s7VQgqJhDK66iGI lXeWljmZ6k5XjRnwmsNoncXTKdLTviNhoB4KcPTqULm8/kGAKhLCJD0fdHxTor05+AjZx3SixcW eHXtvYBAnuEhCfw== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding The video protection region is a reserved memory region that can be used for secure video playback. NVDEC can access this region to decode images into securely. Reviewed-by: Rob Herring (Arm) Signed-off-by: Thierry Reding --- .../devicetree/bindings/gpu/host1x/nvidia,tegra234-nvdec.yaml | 8 ++++= ++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-n= vdec.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-nv= dec.yaml index 4eb325cfd296..bcaaabca945d 100644 --- a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-nvdec.ya= ml +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra234-nvdec.ya= ml @@ -60,6 +60,14 @@ properties: - const: dma-mem - const: write =20 + memory-region: + items: + - description: reference to the video protection memory region + + memory-region-names: + items: + - const: protected + nvidia,memory-controller: $ref: /schemas/types.yaml#/definitions/phandle description: --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B156F481FCF; Fri, 14 Aug 2026 15:29:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721385; cv=none; b=N0IBkykkG6pOLIYq3udPYImVuSI9fACfITLc1OxGg9JlWOJEtkaOnfbFy4QkOeh1SChpz/3dcQZD6M26r3AKSS8RDyIo7NM0j8WrNsLKN78g5A9rz0msHLPmvv+uDBaJ8wn5S+ergsOZ5K+neyEWh7csxiuwURvjRZMMHJV9SEo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721385; c=relaxed/simple; bh=oJmc2yMjXHZBAgsG3MI/UFS/Acfo/2sOqteRP01Z7dM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UruSQlbMikuyY27c3c42j5nzxIeaihZWqqgixtL86UpdaaA/6Se7iKvYjmLfKb3uFklzI7+Dxyqv/65Ou+p65uLG9Pi+/vurIUmhj+twjYM1U5O49jLQsl1eYi2GZPRhfVJ1IX4rofjm3F2FcbWhPxspet2M9u/FCkNTitHUjNY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=H8fMWOsQ; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="H8fMWOsQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9BC061F00A3A; Fri, 14 Aug 2026 15:29:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721383; bh=tvyd01m5FmUtu3q6l/t0/X1UQi3FbzSuZHwJCHFz3QM=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=H8fMWOsQ2nY7rRYNXdC3Kxk3tP32Auay7NWiyJ65BNvLq38ZZSecEDKR36HmgNk7+ s3Z2rCk2cKe57LilC2o4MM4r9AMF1pxtXhXVntG0Y7DTuY4QHF6MUCMYnpIT3sNeCs 0U+jK63PneIHswJSFebrqfu0HdvP7pHlcGdZrXlYUQn6kUgvMdVEc6kb9nB1sd3p3I uATLMVHvhtHrm6Z3HDjq1GXQZ0m/nqvNxNJC57soSA9lreXCC0LBBp1tHEywyqrlLb NtWno1ofLqFfZl9KpPx7NGeFY5mLzpelryD8eu9n3eCqNhRiaR60wyRSRJKIIKQ5K9 qyZYSLHwIvD1w== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:12 +0200 Subject: [PATCH v5 04/10] bitmap: Add bitmap_allocate() function Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-4-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=2300; i=treding@nvidia.com; h=from:subject:message-id; bh=wRtcGoPPtBVnuqzylzx/Ya02XdoWLRjgy09wPiiWfTU=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRYn56w7dlp0eX7ejF+F4kvYppmzV/e3SCSG vxjhHD4yLWJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80WAAKCRDdI6zXfz6z obboEAC10PUKwRv39HTc5k+g4sCaMv90YqNR/4He93iCJA/t3/bYB392GuvI40e9i2b+/THKgUv owyRKvDL45Y4tLql/kYzRamz9NA9LdbBSs+ALLU7UX6K0hB081zMAGWc60XL5xShzAbvzibh6LE Fcm9PIozUNxtcXlYkrNlXUMOFJLN8mURsKvTmSFouWuQz4JpOLeCnBlLu5kr+IRVKq5cdoINN/a Hzj2JnV698uLUjjhtSdJB4o3vQePF6pdPbqW4OP7luNAhDEoTa9CATJYbSxPZZ5ANeliBOT9wor JbX5uyBlr1UDan0Y4nFQrXn1fYI3sRGT8uiHBnyBcJL5PQuGoXB1SCplKEPypB5tJ0DS1J6cCAq JQas5RDquiISPuJiUWJidJ4ziQT1a/yMHfDtZQF3aSwVJWMx64oD1pevUM3mhWEvkMxyaXG+VvN YJkx1v5lrMEpFxhFCjKEfg9eowCVBx82wk259dPU7bjlFrLrtb79fgN53JFj/cQ0Km50AOL1tm1 26P/+JanmM3fSChpg06noCAj0hPxJuseICEeXumslr79YvJzC/24j36oU9o/y0EiyIBk9EDvjTV THzOJwt4mjTsP+pyu8XGptz4JPKzIveXxg+hFh09CEdbcj0Ad9lJdbj9DImFUv9p3LkDFqxBQC1 XuMpNPPr6dO7P4g== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding This is similar to bitmap_allocate_region() but allows allocation of non-power of two pages/bits. While at it, reimplement bitmap_allocate_region() in terms of this new helper to remove a sliver of code duplication. Signed-off-by: Thierry Reding --- include/linux/bitmap.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 7df1573a409c..c2ab02985b5f 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -716,10 +716,10 @@ void bitmap_release_region(unsigned long *bitmap, uns= igned int pos, int order) } =20 /** - * bitmap_allocate_region - allocate bitmap region + * bitmap_allocate - allocate bitmap region * @bitmap: array of unsigned longs corresponding to the bitmap * @pos: beginning of bit region to allocate - * @order: region size (log base 2 of number of bits) to allocate + * @len: number of bits to allocate * * Allocate (set bits in) a specified region of a bitmap. * @@ -727,16 +727,31 @@ void bitmap_release_region(unsigned long *bitmap, uns= igned int pos, int order) * free (not all bits were zero). */ static __always_inline -int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int or= der) +int bitmap_allocate(unsigned long *bitmap, unsigned int pos, unsigned int = len) { - unsigned int len =3D BIT(order); - if (find_next_bit(bitmap, pos + len, pos) < pos + len) return -EBUSY; bitmap_set(bitmap, pos, len); return 0; } =20 +/** + * bitmap_allocate_region - allocate bitmap region + * @bitmap: array of unsigned longs corresponding to the bitmap + * @pos: beginning of bit region to allocate + * @order: region size (log base 2 of number of bits) to allocate + * + * Allocate (set bits in) a specified region of a bitmap. + * + * Returns: 0 on success, or %-EBUSY if specified region wasn't + * free (not all bits were zero). + */ +static __always_inline +int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int or= der) +{ + return bitmap_allocate(bitmap, pos, BIT(order)); +} + /** * bitmap_find_free_region - find a contiguous aligned mem region * @bitmap: array of unsigned longs corresponding to the bitmap --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 69594483825; Fri, 14 Aug 2026 15:29:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721387; cv=none; b=E7qYBijTk3Pmw8il5mku604XTGXUSnjet1/xVhni/Y8PQXAS8UZcvJuHx2+ad5WqgdQjsXzOi5GrzpOBTWIL0Edp54lw1reOyb99SEGqP8oJIK+UXnUFqxp8vti4luu1VjMcpQu256CDRyoPJzBR6lIQZKjhwdwbMcjBax6TIeU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721387; c=relaxed/simple; bh=XAFz+SlRkr3oLsGhWb+vz2UMbT7IzvhZ4e5TecR8Zh0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QKLztBZfKHjmzPz4IIGGxh3B29S2IKGb+m1xlK6PzWexu15q5Eli9yoQY1IYvdq/payWo+vTia6ce4GkW6+E6wu4iOC0QGnRvQuxIYQxprmCfyXvY0oams2qaqjL79Qwy9DneDeYpnDuRWKTDP9QeDCjdduqkKiETsDQUVGhU8E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TScaB6W5; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TScaB6W5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6EE2E1F00A3A; Fri, 14 Aug 2026 15:29:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721386; bh=B53xWDqmYfvZa6yJt4TYLNzQ/iHTo3TnmEOY4voWzrw=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=TScaB6W55A1XzLOs9xyIaRwxfTpsnVeQy7Hw7gY4T0vzkPHa34BHGIDl8dXxlmPht Is1oNRF6tUrbIt7Qn2doBmlcD9HW2DAGec1qhE22heDpRb83FehxKyjZr5fuJkrKW6 Bru6wOnkqW/05EEoZrUeEksj0uXPp+OnrWt7vbXt1c/A3mZBA9OROw6aNhUqA5o8Ln 7LnZ7ybAclo26+0pH5wtoqhZM6Aa9UwHim0oPTym/+I8e4YImUfQNyQo+2zdEMQB/+ bylEwJPtSgZuQLH3Q/2qfPqt/YYHNeK13XIfa0Xw0yzHjw/tamf12H85kdbxCz/dXU YcHKHjrYYgMlg== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:13 +0200 Subject: [PATCH v5 05/10] mm/cma: Introduce cma_alloc_at() API Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-5-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=8085; i=treding@nvidia.com; h=from:subject:message-id; bh=97QBeL/p4gnA3oWbuc8nrY9frCucOEa/VZaNaGGd800=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRY/u1pTDN2EuvbJ7MtOiBc2NgUeKpZTxbki m2HnepxKLmJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80WAAKCRDdI6zXfz6z odAOD/9kLPUFEP21LxFVMtux6KprhSVJgcaJFoEJBtTsoAw9oyP8EJoYCN1UmWZavseTSU+qYOF 71q7NwUwVjtPJCzL0j6fZBN2xx6OYV4CP/QrNI3z07bZQQQirkcEEgIIQXkG0o8ZeSgMSgVxcT/ geQuWUaIIwi0HVsEwLGeC29XAGVCTMqfm8seg9Lgxaz8UnzYThlmYepyarN3mMN/dfFWioWSxYD F9uyN+i8CMONXACTPK0UygpJrcGSNWoH0wrTZrHDmYnX/OTTPFoWB4ZeJpFB75H8AWhVJRqHrN+ cxdolngsD60237ZleJ2YJoe/cZwyzYbxOS06un7Tz36PRcdoS6WUwgIghINL4gk1eMKDSrhhEHM b4WufrnUPOVtCXShNDlxtWdnxmaEiOr8cvgkCIwRkH6pmreX0N702LI5E0gAKEawmhlw3PadbEn UPYrzoCV3B1eJrqLTp33GG/zoNTkOUNplGQT/Sfj7qIPllj+myGVgRCHhZUtCDX6++OAqQ+tIbW wKEikbC1BNgSGm+dmDCi0USaL6909+rLzp1TEA4mBOzn34trVi4avbnntXA4+AN4Z9/1JFHvQs/ 2DXDyShuozSi12MOxFQB28lWF9cLduNXpxloQeKFwJ41Hpf99xGCa+Cct+k2qHPNlYj1UNMTSbA UhYxhrn/nZbNkcg== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding This API can be used to allocate a number of CMA pages starting at a fixed offset. This is useful, for example, if the CMA area is used as backing storage for a nested allocator that has stricter requirements than CMA itself. Suggested-by: Marek Szyprowski Signed-off-by: Thierry Reding --- include/linux/cma.h | 4 ++ include/trace/events/cma.h | 63 +++++++++++++++++++ mm/cma.c | 148 +++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 215 insertions(+) diff --git a/include/linux/cma.h b/include/linux/cma.h index 8555d38a97b1..844404459a42 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -49,11 +49,15 @@ extern int cma_init_reserved_mem(phys_addr_t base, phys= _addr_t size, struct cma **res_cma); extern struct page *cma_alloc(struct cma *cma, unsigned long count, unsign= ed int align, bool no_warn); +extern struct page *cma_alloc_at(struct cma *cma, unsigned long offset, + unsigned long count, bool no_warn); extern bool cma_release(struct cma *cma, const struct page *pages, unsigne= d long count); =20 struct page *cma_alloc_frozen(struct cma *cma, unsigned long count, unsigned int align, bool no_warn); struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order= ); +struct page *cma_alloc_at_frozen(struct cma *cma, unsigned long offset, + unsigned long count, bool no_warn); bool cma_release_frozen(struct cma *cma, const struct page *pages, unsigned long count); =20 diff --git a/include/trace/events/cma.h b/include/trace/events/cma.h index 37195edf2498..00b622a9da97 100644 --- a/include/trace/events/cma.h +++ b/include/trace/events/cma.h @@ -132,6 +132,69 @@ TRACE_EVENT(cma_alloc_busy_retry, __entry->align) ); =20 +TRACE_EVENT(cma_alloc_at_start, + + TP_PROTO(const char *name, unsigned long pfn, + unsigned long request_count, unsigned long available_count, + unsigned long total_count), + + TP_ARGS(name, pfn, request_count, available_count, total_count), + + TP_STRUCT__entry( + __string(name, name) + __field(unsigned long, pfn) + __field(unsigned long, request_count) + __field(unsigned long, available_count) + __field(unsigned long, total_count) + ), + + TP_fast_assign( + __assign_str(name); + __entry->pfn =3D pfn; + __entry->request_count =3D request_count; + __entry->available_count =3D available_count; + __entry->total_count =3D total_count; + ), + + TP_printk("name=3D%s pfn=3D%lx, request_count=3D%lu available_count=3D%lu= total_count=3D%lu", + __get_str(name), + __entry->pfn, + __entry->request_count, + __entry->available_count, + __entry->total_count) +); + +TRACE_EVENT(cma_alloc_at_finish, + + TP_PROTO(const char *name, unsigned long pfn, const struct page *page, + unsigned long count, int errorno), + + TP_ARGS(name, pfn, page, count, errorno), + + TP_STRUCT__entry( + __string(name, name) + __field(unsigned long, pfn) + __field(const struct page *, page) + __field(unsigned long, count) + __field(int, errorno) + ), + + TP_fast_assign( + __assign_str(name); + __entry->pfn =3D pfn; + __entry->page =3D page; + __entry->count =3D count; + __entry->errorno =3D errorno; + ), + + TP_printk("name=3D%s pfn=3D0x%lx page=3D%p count=3D%lu errorno=3D%d", + __get_str(name), + __entry->pfn, + __entry->page, + __entry->count, + __entry->errorno) +); + #endif /* _TRACE_CMA_H */ =20 /* This part must be outside protection */ diff --git a/mm/cma.c b/mm/cma.c index a10ea37a261d..1e1ebae79090 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -936,6 +936,141 @@ struct page *cma_alloc_frozen_compound(struct cma *cm= a, unsigned int order) return __cma_alloc_frozen(cma, 1 << order, order, gfp); } =20 +static int cma_range_alloc_at(struct cma *cma, struct cma_memrange *cmr, + unsigned long offset, unsigned long count, + struct page **pagep, gfp_t gfp) +{ + struct page *page =3D NULL; + unsigned long pfn; + int ret =3D -EBUSY; + + spin_lock_irq(&cma->lock); + + /* + * If the request is larger than the available number of pages, stop + * right away. + */ + if (count > cma->available_count) + goto unlock; + + ret =3D bitmap_allocate(cmr->bitmap, offset, count); + if (ret < 0) + goto unlock; + + pfn =3D cmr->base_pfn + offset; + page =3D pfn_to_page(pfn); + + /* + * Do not hand out page ranges that are not contiguous, so + * callers can just iterate the pages without having to worry + * about these corner cases. + */ + if (!page_range_contiguous(page, count)) { + pr_warn_ratelimited("%s: %s: skipping non-contiguous area [0x%lx-0x%lx]", + __func__, cma->name, pfn, pfn + count - 1); + ret =3D -EBUSY; + goto clear; + } + + cma->available_count -=3D count; + + /* + * It's safe to drop the lock here. We've marked this region for + * our exclusive use. If the migration fails we will take the + * lock again and unmark it. + */ + spin_unlock_irq(&cma->lock); + + mutex_lock(&cma->alloc_mutex); + ret =3D alloc_contig_frozen_range(pfn, pfn + count, ACR_FLAGS_CMA, gfp); + mutex_unlock(&cma->alloc_mutex); + + if (ret < 0) + goto free; + + *pagep =3D page; + + return 0; + +free: + /* we need to reacquire the lock to clean up the internal state */ + spin_lock_irq(&cma->lock); + cma->available_count +=3D count; +clear: + bitmap_clear(cmr->bitmap, offset, count); +unlock: + spin_unlock_irq(&cma->lock); + return ret; +} + +static struct page *__cma_alloc_at_frozen(struct cma *cma, unsigned long o= ffset, + unsigned long count, gfp_t gfp) +{ + const char *name =3D cma ? cma->name : NULL; + struct page *page =3D NULL; + int ret =3D -ENOMEM, r; + unsigned long i; + + if (!cma || !cma->count) + return page; + + pr_debug("%s(cma %p, name: %s, offset %lu, count %lu)\n", __func__, + (void *)cma, cma->name, offset, count); + + if (!count) + return page; + + trace_cma_alloc_at_start(name, offset, count, cma->available_count, + cma->count); + + for (r =3D 0; r < cma->nranges; r++) { + page =3D NULL; + + ret =3D cma_range_alloc_at(cma, &cma->ranges[r], offset, count, + &page, gfp); + if (ret !=3D -EBUSY || page) + break; + } + + /* + * CMA can allocate multiple page blocks, which results in different + * blocks being marked with different tags. Reset the tags to ignore + * those page blocks. + */ + if (page) { + for (i =3D 0; i < count; i++) + page_kasan_tag_reset(page + i); + } + + if (ret && !(gfp & __GFP_NOWARN)) { + pr_err_ratelimited("%s: %s: alloc failed, request: %lu, %lu pages, ret: = %d\n", + __func__, cma->name, offset, count, ret); + cma_debug_show_areas(cma); + } + + pr_debug("%s(): returned %p\n", __func__, page); + trace_cma_alloc_at_finish(name, page ? page_to_pfn(page) : 0, page, + count, ret); + + if (page) { + count_vm_event(CMA_ALLOC_SUCCESS); + cma_sysfs_account_success_pages(cma, count); + } else { + count_vm_event(CMA_ALLOC_FAIL); + cma_sysfs_account_fail_pages(cma, count); + } + + return page; +} + +struct page *cma_alloc_at_frozen(struct cma *cma, unsigned long offset, + unsigned long count, bool no_warn) +{ + gfp_t gfp =3D GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0); + + return __cma_alloc_at_frozen(cma, offset, count, gfp); +} + /** * cma_alloc() - allocate pages from contiguous area * @cma: Contiguous memory region for which the allocation is performed. @@ -959,6 +1094,19 @@ struct page *cma_alloc(struct cma *cma, unsigned long= count, } EXPORT_SYMBOL_GPL(cma_alloc); =20 +struct page *cma_alloc_at(struct cma *cma, unsigned long pfn, + unsigned long count, bool no_warn) +{ + struct page *page; + + page =3D cma_alloc_at_frozen(cma, pfn, count, no_warn); + if (page) + set_pages_refcounted(page, count); + + return page; +} +EXPORT_SYMBOL_GPL(cma_alloc_at); + static struct cma_memrange *find_cma_memrange(struct cma *cma, const struct page *pages, unsigned long count) { --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A6DB481FA5; Fri, 14 Aug 2026 15:29:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721390; cv=none; b=Vg+Fw7zXiUgpLJ0U4yj3QCPX63utVnAJY6g7I/TzPopd5JztPNCEqMt7sULqJk1D+UwFYVv/eyFkE8VUfn9DLtpAw8+nmzuF7/+2BEaDcqButUfSxpGFBsEj0puUHSydkc3TLuCWujvkqzdJOrBrox5zMqSPsjRdI5s/72pdmf8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721390; c=relaxed/simple; bh=YKAfeUFKRAPjvhpRQgV8Bmpb0xoRLjn0rVI26lpgxS4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=g0xmEtxwxcLk5+70k/wxrQdju1ZHTPOihhZvE3EBxS32yR1g6t36+HrOTECoJeivwSa/BdeTpKWmCbkwvWexoFvkyCLvHE5dSUyvPyCLwaONjVDbPZa0pfd8sx/V80EAvY2bfhGkv+QDmJIqrSOoPJ1apV0Db7ElJsc3JXXtXw8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ln9neMLZ; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ln9neMLZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3D6D21F00A3A; Fri, 14 Aug 2026 15:29:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721389; bh=2BzkMYY6PcCnjt83f3h4QxpYa7pa6qO3m5eLZk1ygvA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Ln9neMLZiNxLoktO8600yFMf9c696Sy2dR+14AC2Hs2g+Xi89Txg/bSadDBOpbwcv BjvkAaOqDRQNOHgRnewOmAypSnsKE+p2FrMqlmZ2f8C+cVq58bhg6cssdS3UQxJfKI 4FYONwhecSKXCZPQ+MF/0p1j/7vXqbFHU902HXezxWfV29DnYWXw43Mql6vCbCX0Uw PUFhHldktEKV7l/kU0JqP1PDRyq2wf7e8rQap5YtVkKbAoJJVLBtknA4AFMTdxu7VN 0tsKp78ANWAq5hhJVzfZBWQfwVhmQXBNALrKFZv6gzQIZaf9k6CQ9cYKzWTXlCcb82 T/Ew0aZzK5jXA== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:14 +0200 Subject: [PATCH v5 06/10] dma-buf: heaps: Add debugfs support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-6-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3268; i=treding@nvidia.com; h=from:subject:message-id; bh=HQOwe346eKLILGUmI6Jj24mMizqBZC+UN1JuTqxPA6o=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRYmBB73yTjIp5WYf1lpDC/x5XoUQVQFUBsE No/1I1LYFCJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80WAAKCRDdI6zXfz6z oZWhD/4hADdFVVuUvAoZK8vnwfXJ/xRPQxPYCgpzlO8eC/xBPUIs2BUZCanYUlRY/Z96oGX7ivB u+VLQ/yymD2KtVUK1Cr5+MZNleFgmE6dONc2BdeToY3RfHjQq1apoi+paNZvQeZIhMH77FHFGbc kpgO9CLRwB+2rMDRspKHQoxXt3Iz3v3DvXJsZQvKTEwlrDGntDF+kLyrihrF6zLL/8aXexV1aX9 UAqqpn/zR04SbLtYQT08gdMQ2N9fuxXs5V+DEKW10Pq7UmbnEp0YzH9bRFAs0X99ULNLbggnRPh ikGbklpZPQkphOWasX007jnCYHoPGGfVannQFtE+lCH5KgVA7yRqjaYyF0/GEpZtIJBYBVBu6TN 78xWK9CyM6mluHtF4kr3sF0b3zNf/ElnTuqgCVRrq5WIqG4CF4mb3yuubfvDkPAUL//ToIfmVD1 +JnhzKzBJqKSyxC959QmwhelV/tls+oASyCVKUMSf1vwc+1PdNV+9ViaCDF5gXT+4SrVbXAXoPA fzKUZ2FmUvkjCxr+6BMxmnZLmRhFs5ge/h+xS4FDsZLGdgtT7bQJqLCL+oZFoM2A79WT+tP5cmt 52I38IluSVfOTmhe4upYRzOlQUw0hLB4XcPa2mI8dPQWD0/iwaaZGaTIoQg+c9qj3TiWs8Q9/p1 3YgAjy39e97CSgA== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding Add a callback to struct dma_heap_ops that heap providers can implement to show information about the state of the heap in debugfs. A top-level directory named "dma_heap" is created in debugfs and individual files will be named after the heaps. Reviewed-by: Maxime Ripard Signed-off-by: Thierry Reding --- Changes in v5: - fix failure handling during debugfs root directory creation - add more cleanup to the newly introduced dma_heap_exit() --- drivers/dma-buf/dma-heap.c | 52 ++++++++++++++++++++++++++++++++++++++++++= ++++ include/linux/dma-heap.h | 2 ++ 2 files changed, 54 insertions(+) diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c index 3937dd41bb0f..f279b8fdd3ce 100644 --- a/drivers/dma-buf/dma-heap.c +++ b/drivers/dma-buf/dma-heap.c @@ -7,6 +7,7 @@ */ =20 #include +#include #include #include #include @@ -225,6 +226,40 @@ const char *dma_heap_get_name(struct dma_heap *heap) } EXPORT_SYMBOL_NS_GPL(dma_heap_get_name, "DMA_BUF_HEAP"); =20 +#ifdef CONFIG_DEBUG_FS +static int dma_heap_debug_show(struct seq_file *s, void *unused) +{ + struct dma_heap *heap =3D s->private; + int err =3D 0; + + if (heap->ops && heap->ops->show) + err =3D heap->ops->show(s, heap); + + return err; +} +DEFINE_SHOW_ATTRIBUTE(dma_heap_debug); + +static struct dentry *dma_heap_debugfs_dir; + +static void dma_heap_init_debugfs(void) +{ + dma_heap_debugfs_dir =3D debugfs_create_dir("dma_heap", NULL); +} + +static void dma_heap_exit_debugfs(void) +{ + debugfs_remove_recursive(dma_heap_debugfs_dir); +} +#else +static void dma_heap_init_debugfs(void) +{ +} + +static void dma_heap_exit_debugfs(void) +{ +} +#endif + /** * dma_heap_add - adds a heap to dmabuf heaps * @exp_info: information needed to register this heap @@ -299,6 +334,13 @@ struct dma_heap *dma_heap_add(const struct dma_heap_ex= port_info *exp_info) =20 /* Add heap to the list */ list_add(&heap->list, &heap_list); + +#ifdef CONFIG_DEBUG_FS + if (heap->ops && heap->ops->show) + debugfs_create_file(heap->name, 0444, dma_heap_debugfs_dir, + heap, &dma_heap_debug_fops); +#endif + mutex_unlock(&heap_list_lock); =20 return heap; @@ -335,6 +377,16 @@ static int dma_heap_init(void) } dma_heap_class->devnode =3D dma_heap_devnode; =20 + dma_heap_init_debugfs(); + return 0; } subsys_initcall(dma_heap_init); + +static void __exit dma_heap_exit(void) +{ + dma_heap_exit_debugfs(); + class_destroy(dma_heap_class); + unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); +} +__exitcall(dma_heap_exit); diff --git a/include/linux/dma-heap.h b/include/linux/dma-heap.h index 648328a64b27..1c9bed1f4dde 100644 --- a/include/linux/dma-heap.h +++ b/include/linux/dma-heap.h @@ -12,6 +12,7 @@ #include =20 struct dma_heap; +struct seq_file; =20 /** * struct dma_heap_ops - ops to operate on a given heap @@ -24,6 +25,7 @@ struct dma_heap_ops { unsigned long len, u32 fd_flags, u64 heap_flags); + int (*show)(struct seq_file *s, struct dma_heap *heap); }; =20 /** --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 540B6483BFF; Fri, 14 Aug 2026 15:29:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721394; cv=none; b=rBCo5mudmAIMHINBB9L8HrKq6C3nDjcJYxmYikLw519qxVy+PAv8hTc3A0/yx6sHDZnD2Z3ORYEupQWgHjkL1Hl4zAv1rBs5sXaq1oBx6zPtrhz78/CxcgrYhoPkgL6Ohx7cJSD2e0x8ea0yiTSSwyMrlN7GJdX2ExKVXlnBYaw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721394; c=relaxed/simple; bh=+1QqWoCFjcTbrJvIV2upcMgHCewUWwx4m9UcepmGBRM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=G/46V+XhJkcUpVYx1+rnJI8qnPsP0C7pNHnnIusCJIsCA+P6iBWpBMHzPSAQQiBylQvBfLQTB/ZJF+YfzaJpnydaAvPwj+5rXijaO5WlOLJn0OWx8tv4J1qYCKAIoahTkH8pDElJOjgDAnFKVb4GVTPdls3B9AaRSVHxworxIQc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=c69NEa0A; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="c69NEa0A" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 11F641F000E9; Fri, 14 Aug 2026 15:29:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721392; bh=qg4+Lu74mRxW0xLkyK7n6LXVB/VbiYq9VC3Bk0Z333Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=c69NEa0ABUjbPe1s+Xd5Y7fAOgTuSCHgdSF7hxbaxuhnIYKdcOiqsuM6bTxF6F6J7 AXauYsPv/ShulXbCCpJYDj8NJX7C5nRH1gNdiHSfXRw2Dt+wiQBAtF0WOL3QvK1HdZ 3Tog295vw+ZKcEfh1yygVnvMJHlmjBlpWoMsqdLCdn/6I0TISUZZdclGLOH9QasRe1 LhdWyDykW3iYsE12U6zBO6sMn2vHYLfmddSFqX2OxI9SbzqE7uw63dU4C1yVLL0Ipe fgxJbnf7Yvtst/BMNFIakLuvmQIm5LWWa0V948kEQabS8Pb4hllfKCptkuzb3SaW3T gTyNZ/tQm/DEg== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:15 +0200 Subject: [PATCH v5 07/10] dma-buf: heaps: Add support for Tegra VPR Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-7-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=41961; i=treding@nvidia.com; h=from:subject:message-id; bh=6rkfJol37J+EZhflynwBy3XWUUY7Fg+SQK7I8bwOjPY=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRYTf8eR6qXMcLjtxL89jTCuZJVeZmXtDrBk JAnwBbhHACJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80WAAKCRDdI6zXfz6z oSq/EAC+A2n69sw5AmvDBoSIt+8xppEZyJxsqNPIPMnRea/0eYjI3z+arlIC6wstYbG1Db0IuTO DdpLqu/LlkkeIhik/gk1bK7M2nlzdqorZVjDNFaz28j7viqEtJMR+fEn29sut8UnDHEAWhHQpvZ 4Z8ulEcIr4Cbjnx07k4e5QQHmlK0yftqOt5nrYaNah5bv3j3Pl/oNaR38Lb4SogPYnXLVKz7xJn r45zxvKASkF67EsLX/9OAx2Mp5KrEL+Zuphom1GipsoGDd4EfLNZFk5sf9AJBKsiORjniIOKUpb LQso2+jrTg6i7Vzo9n20I0NdMmHzKFq2yPvjMk77ER3OJf5fYk6vjd+EqzOiMZBa6iKv10ejwpm qC477M9BrkDu/2FEoUte0mq9dM609JEt8eiBVbhOfUxZojtO8nIWpOpbHl4wOukid4dbILQkMyR i9tlEIXmELsxFi8jXS6xJ3cX/9yY73HXYOVN6wY+W6x0JSejipMwi4MbX1NxuPc/EWexptmXpTD ZmYqZSzcPZg8kTsuDO7dxqw+AH3iZhrq6OKdGGXgWu6lau5IUkc+xyUFZxFTN07XXNYR+iryoSy b7vU5Jb2+wtZ5HT2Tyl4WXXbAFXFp9zY4r+mQ8Q/ZVoAg0pALfE5j+UiEmCBl1NDzyNv8h1/HWB 0DH5bZETT0Wz8MQ== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding NVIDIA Tegra SoCs commonly define a Video-Protection-Region, which is a region of memory dedicated to content-protected video decode and playback. This memory cannot be accessed by the CPU and only certain hardware devices have access to it. Expose the VPR as a DMA heap so that applications and drivers can allocate buffers from this region for use-cases that require this kind of protected memory. VPR has a few very critical peculiarities. First, it must be a single contiguous region of memory (there is a single pair of registers that set the base address and size of the region), which is configured by calling back into the secure monitor. The memory region also needs to quite large for some use-cases because it needs to fit multiple video frames (8K video should be supported), so VPR sizes of ~2 GiB are expected. However, some devices cannot afford to reserve this amount of memory for a particular use-case, and therefore the VPR must be resizable. Unfortunately, resizing the VPR is slightly tricky because the GPU found on Tegra SoCs must be in reset during the VPR resize operation. This is currently implemented by freezing all userspace processes and calling invoking the GPU's freeze() implementation, resizing and the thawing the GPU and userspace processes. This is quite heavy-handed, so eventually it might be better to implement thawing/freezing in the GPU driver in such a way that they block accesses to the GPU so that the VPR resize operation can happen without suspending all userspace. In order to balance the memory usage versus the amount of resizing that needs to happen, the VPR is divided into multiple chunks. Each chunk is implemented as a CMA area that is completely allocated on first use to guarantee the contiguity of the VPR. Once all buffers from a chunk have been freed, the CMA area is deallocated and the memory returned to the system. Signed-off-by: Thierry Reding --- Changes in v5: - use newly introduced cma_alloc_at() and work with a single CMA area - setup CMA early and initialize VPR later during boot - remove some unused variables - use kalloc_objs() Changes in v4: - address Sashiko and checkpatch comments - fully remove from linear map while chunks are allocated - improve error handling - remove freezer support Changes in v3: - use set_memory_device() and set_memory_normal() helpers - use kzalloc_obj() instead of kzalloc() with sizeof() Changes in v2: - cluster allocations to reduce the number of resize operations - support cross-chunk allocation --- drivers/dma-buf/heaps/Kconfig | 12 + drivers/dma-buf/heaps/Makefile | 1 + drivers/dma-buf/heaps/tegra-vpr.c | 1410 +++++++++++++++++++++++++++++++++= ++++ include/trace/events/tegra_vpr.h | 57 ++ 4 files changed, 1480 insertions(+) diff --git a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig index bb729e91545c..8909330bfaa2 100644 --- a/drivers/dma-buf/heaps/Kconfig +++ b/drivers/dma-buf/heaps/Kconfig @@ -20,3 +20,15 @@ config DMABUF_HEAPS_CMA Choose this option to enable dma-buf CMA heap. This heap is backed by the Contiguous Memory Allocator (CMA). If your system has these regions, you should say Y here. + +config DMABUF_HEAPS_TEGRA_VPR + bool "NVIDIA Tegra Video-Protected-Region DMA-BUF Heap" + depends on DMABUF_HEAPS && DMA_CMA + help + Choose this option to enable Video-Protected-Region (VPR) support on + a range of NVIDIA Tegra devices. Access to VPR memory is limited to + a subset of hardware engines and specifically disallowed from the + CPU. The region can be fixed, in which case no linear mapping exists + for the memory, or it can be resizable on systems that want to reuse + the memory for other uses when content-protected video is not played + back. diff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile index 974467791032..265b77a7b889 100644 --- a/drivers/dma-buf/heaps/Makefile +++ b/drivers/dma-buf/heaps/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) +=3D system_heap.o obj-$(CONFIG_DMABUF_HEAPS_CMA) +=3D cma_heap.o +obj-$(CONFIG_DMABUF_HEAPS_TEGRA_VPR) +=3D tegra-vpr.o diff --git a/drivers/dma-buf/heaps/tegra-vpr.c b/drivers/dma-buf/heaps/tegr= a-vpr.c new file mode 100644 index 000000000000..c8d9f9c66dde --- /dev/null +++ b/drivers/dma-buf/heaps/tegra-vpr.c @@ -0,0 +1,1410 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMA-BUF restricted heap exporter for NVIDIA Video-Protection-Region (VP= R) + * + * Copyright (C) 2024-2026 NVIDIA Corporation + */ + +#define pr_fmt(fmt) "tegra-vpr: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#define TEGRA_VPR_MAX_CHUNKS 64 + +struct tegra_vpr; + +struct tegra_vpr_device { + struct list_head node; + struct device *dev; +}; + +struct tegra_vpr_chunk { + phys_addr_t start; + phys_addr_t limit; + size_t size; + + struct tegra_vpr *vpr; + bool invalid; + bool active; + + struct page *start_page; + unsigned int offset; + unsigned long virt; + pgoff_t num_pages; + + unsigned int num_buffers; +}; + +struct tegra_vpr { + struct list_head list; + + struct device_node *dev_node; + unsigned long align; + phys_addr_t base; + phys_addr_t size; + int nid; + + struct list_head buffers; + unsigned long *bitmap; + pgoff_t num_pages; + + /* resizable VPR */ + struct cma *cma; + unsigned long *active; + struct tegra_vpr_chunk *chunks; + unsigned int num_chunks; + struct page *start_page; + bool resizable; + + unsigned int first; + unsigned int last; + + struct list_head devices; + + /** + * @lock: Protects concurrent access to the allocation bitmap, as well + * as the buffers and devices lists. + */ + struct mutex lock; +}; + +static DEFINE_MUTEX(vpr_lock); +static LIST_HEAD(vpr_list); + +struct tegra_vpr_buffer { + struct list_head attachments; + struct tegra_vpr *vpr; + struct list_head list; + + /** + * @lock: Protects concurrent access to the list of attachments. + */ + struct mutex lock; + + struct page **pages; + pgoff_t num_pages; + phys_addr_t start; + phys_addr_t limit; + size_t size; + int pageno; + int order; + + DECLARE_BITMAP(chunks, TEGRA_VPR_MAX_CHUNKS); +}; + +struct tegra_vpr_attachment { + struct device *dev; + struct sg_table sgt; + struct list_head list; +}; + +#define ARM_SMCCC_TE_FUNC_PROGRAM_VPR 0x3 + +#define ARM_SMCCC_VENDOR_SIP_TE_PROGRAM_VPR_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_SIP, \ + ARM_SMCCC_TE_FUNC_PROGRAM_VPR) + +static int tegra_vpr_set(phys_addr_t base, phys_addr_t size) +{ + struct arm_smccc_res res; + + arm_smccc_smc(ARM_SMCCC_VENDOR_SIP_TE_PROGRAM_VPR_FUNC_ID, base, size, + 0, 0, 0, 0, 0, &res); + + return res.a0; +} + +static int tegra_vpr_get_extents(struct tegra_vpr *vpr, phys_addr_t *base, + phys_addr_t *size) +{ + phys_addr_t start =3D ~0, limit =3D 0; + unsigned int i; + + for (i =3D 0; i < vpr->num_chunks; i++) { + struct tegra_vpr_chunk *chunk =3D &vpr->chunks[i]; + + if (chunk->active) { + if (chunk->start < start) + start =3D chunk->start; + + if (chunk->limit > limit) + limit =3D chunk->limit; + } + } + + if (limit > start) { + *size =3D limit - start; + *base =3D start; + } else { + *base =3D *size =3D 0; + } + + return 0; +} + +static int tegra_vpr_resize(struct tegra_vpr *vpr) +{ + struct tegra_vpr_device *node; + phys_addr_t base, size; + int err, status =3D 0; + + err =3D tegra_vpr_get_extents(vpr, &base, &size); + if (err < 0) { + pr_err("%s(): failed to get VPR extents: %d\n", __func__, err); + return err; + } + + list_for_each_entry(node, &vpr->devices, node) { + err =3D pm_generic_freeze(node->dev); + if (err < 0) { + pr_err("failed to freeze %s: %d\n", + dev_name(node->dev), err); + status =3D err; + goto thaw; + } + } + + trace_tegra_vpr_set(base, size); + + err =3D tegra_vpr_set(base, size); + if (err < 0) { + pr_err("failed to secure VPR: %d\n", err); + status =3D err; + } + +thaw: + list_for_each_entry_continue_reverse(node, &vpr->devices, node) { + err =3D pm_generic_thaw(node->dev); + if (err < 0) { + pr_err("failed to thaw %s: %d\n", + dev_name(node->dev), err); + continue; + } + } + + return status; +} + +static int tegra_vpr_chunk_init(struct tegra_vpr *vpr, + struct tegra_vpr_chunk *chunk, + phys_addr_t start, size_t size, + unsigned int order, const char *name) +{ + chunk->start =3D start; + chunk->limit =3D start + size; + chunk->size =3D size; + chunk->vpr =3D vpr; + + chunk->offset =3D (start - vpr->base) >> PAGE_SHIFT; + chunk->num_pages =3D size >> PAGE_SHIFT; + chunk->num_buffers =3D 0; + + /* CMA area is not reserved yet */ + chunk->start_page =3D NULL; + chunk->virt =3D 0; + + return 0; +} + +static void tegra_vpr_chunk_free(struct tegra_vpr_chunk *chunk) +{ +} + +static inline bool tegra_vpr_chunk_is_last(const struct tegra_vpr_chunk *c= hunk) +{ + phys_addr_t limit =3D chunk->vpr->base + chunk->vpr->size; + + return chunk->limit =3D=3D limit; +} + +static inline bool tegra_vpr_chunk_is_leaf(const struct tegra_vpr_chunk *c= hunk) +{ + const struct tegra_vpr_chunk *next =3D chunk + 1; + + if (tegra_vpr_chunk_is_last(chunk)) + return true; + + return !next->active; +} + +static int tegra_vpr_chunk_alloc(struct tegra_vpr_chunk *chunk) +{ + chunk->start_page =3D cma_alloc_at(chunk->vpr->cma, chunk->offset, + chunk->num_pages, false); + if (!chunk->start_page) + return -ENOMEM; + + chunk->virt =3D (unsigned long)page_to_virt(chunk->start_page); + + return 0; +} + +static int tegra_vpr_chunk_activate(struct tegra_vpr_chunk *chunk) +{ + unsigned int num_errors =3D 0; + int err, status =3D 0; + pgoff_t i; + + trace_tegra_vpr_chunk_activate(chunk->start, chunk->limit); + + for (i =3D 0; i < chunk->num_pages; i++) { + err =3D set_direct_map_invalid_noflush(chunk->start_page + i); + if (err) + goto restore; + } + + flush_tlb_kernel_range(chunk->virt, chunk->virt + chunk->size); + chunk->invalid =3D false; + chunk->active =3D true; + + return 0; + +restore: + status =3D err; + + while (i--) { + err =3D set_direct_map_default_noflush(chunk->start_page + i); + if (err) + num_errors++; + } + + flush_tlb_kernel_range(chunk->virt, chunk->virt + chunk->size); + chunk->invalid =3D num_errors > 0; + + return status; +} + +static int tegra_vpr_chunk_deactivate(struct tegra_vpr_chunk *chunk) +{ + unsigned int num_errors =3D 0; + int err, status =3D 0; + pgoff_t i; + + if (!chunk->active) + return 0; + + /* do not deactivate if there are buffers left in this chunk */ + if (WARN_ON(chunk->num_buffers > 0)) + return -EBUSY; + + trace_tegra_vpr_chunk_deactivate(chunk->start, chunk->limit); + + for (i =3D 0; i < chunk->num_pages; i++) { + err =3D set_direct_map_default_noflush(chunk->start_page + i); + if (err) + goto restore; + } + + flush_tlb_kernel_range(chunk->virt, chunk->virt + chunk->size); + chunk->invalid =3D false; + chunk->active =3D false; + + return 0; + +restore: + status =3D err; + + while (i--) { + err =3D set_direct_map_invalid_noflush(chunk->start_page + i); + if (err) + num_errors++; + } + + flush_tlb_kernel_range(chunk->virt, chunk->virt + chunk->size); + chunk->invalid =3D num_errors > 0; + + return status; +} + +static void tegra_vpr_chunk_release(struct tegra_vpr_chunk *chunk) +{ + if (!WARN_ON(chunk->active || chunk->invalid)) { + cma_release(chunk->vpr->cma, chunk->start_page, + chunk->num_pages); + chunk->start_page =3D NULL; + chunk->virt =3D 0; + } +} + +static bool tegra_vpr_chunk_overlaps(struct tegra_vpr_chunk *chunk, + unsigned int start, unsigned int limit) +{ + unsigned int first =3D chunk->offset; + unsigned int last =3D chunk->offset + chunk->num_pages - 1; + + if (last < start || first >=3D limit) + return false; + + return true; +} + +static int tegra_vpr_activate_chunks(struct tegra_vpr *vpr, + struct tegra_vpr_buffer *buffer) +{ + DECLARE_BITMAP(dirty, vpr->num_chunks); + unsigned int i, bottom, top; + int err =3D 0, ret; + + bitmap_zero(dirty, vpr->num_chunks); + + /* activate any inactive chunks that overlap this buffer */ + for_each_set_bit(i, buffer->chunks, vpr->num_chunks) { + struct tegra_vpr_chunk *chunk =3D &vpr->chunks[i]; + + if (chunk->active) + continue; + + err =3D tegra_vpr_chunk_alloc(chunk); + if (err < 0) + goto deactivate; + + err =3D tegra_vpr_chunk_activate(chunk); + if (err < 0) { + tegra_vpr_chunk_release(chunk); + goto deactivate; + } + + set_bit(i, vpr->active); + set_bit(i, dirty); + } + + /* + * Activating chunks above may have created holes, but since the VPR + * can only ever be a single contiguous region, make sure to activate + * any missing chunks. + */ + for_each_clear_bitrange(bottom, top, vpr->active, vpr->num_chunks) { + /* inactive chunks at the bottom or the top are harmless */ + if (bottom =3D=3D 0 || top =3D=3D vpr->num_chunks) + continue; + + for (i =3D bottom; i < top; i++) { + struct tegra_vpr_chunk *chunk =3D &vpr->chunks[i]; + + err =3D tegra_vpr_chunk_alloc(chunk); + if (err < 0) + goto deactivate; + + err =3D tegra_vpr_chunk_activate(chunk); + if (err < 0) { + tegra_vpr_chunk_release(chunk); + goto deactivate; + } + + set_bit(i, vpr->active); + set_bit(i, dirty); + } + } + + /* if any chunks have been activated, VPR needs to be resized */ + if (!bitmap_empty(dirty, vpr->num_chunks)) { + err =3D tegra_vpr_resize(vpr); + if (err < 0) { + pr_err("failed to grow VPR: %d\n", err); + goto deactivate; + } + } + + /* increment buffer count for each chunk */ + for_each_set_bit(i, buffer->chunks, vpr->num_chunks) + vpr->chunks[i].num_buffers++; + + return 0; + +deactivate: + /* deactivate any of the previously inactive chunks on failure */ + for_each_set_bit(i, dirty, vpr->num_chunks) { + struct tegra_vpr_chunk *chunk =3D &vpr->chunks[i]; + + ret =3D tegra_vpr_chunk_deactivate(chunk); + if (WARN_ON(ret < 0)) { + pr_err("failed to deactivate chunk #%u: %d\n", i, ret); + } else { + tegra_vpr_chunk_release(chunk); + clear_bit(i, vpr->active); + } + } + + return err; +} + +/* + * Retrieve the range of pages within the activate region of the VPR. + */ +static bool tegra_vpr_get_active_range(struct tegra_vpr *vpr, + unsigned int *first, + unsigned int *last) +{ + unsigned long i, j; + + i =3D find_first_bit(vpr->active, vpr->num_chunks); + if (i >=3D vpr->num_chunks) + return false; + + j =3D find_last_bit(vpr->active, vpr->num_chunks); + if (j >=3D vpr->num_chunks) + return false; + + *first =3D vpr->chunks[i].offset; + *last =3D vpr->chunks[j].offset + vpr->chunks[j].num_pages; + + return true; +} + +/* + * Try to find and allocate a free region within a specific page range. + * Returns the page number if successful, -ENOSPC otherwise. + * + * This function mimics bitmap_find_free_region() but restricts the search + * to a specific range to enable allocation within individual chunks. + */ +static int tegra_vpr_find_free_region_in_range(struct tegra_vpr *vpr, + unsigned int start_page, + unsigned int end_page, + unsigned int num_pages, + unsigned int align) +{ + unsigned int pos, next =3D ALIGN(start_page, align); + + /* Scan through aligned positions, trying to allocate at each one */ + for (pos =3D next; pos + num_pages <=3D end_page; pos =3D next) { + next =3D find_next_bit(vpr->bitmap, pos + num_pages, pos); + + if (next >=3D pos + num_pages) { + bitmap_set(vpr->bitmap, pos, num_pages); + return pos; + } + + next =3D find_next_zero_bit(vpr->bitmap, vpr->num_pages, next); + next =3D ALIGN(next, align); + } + + return -ENOSPC; +} + +static int tegra_vpr_find_free_region(struct tegra_vpr *vpr, + unsigned int num_pages, + unsigned long align) +{ + return tegra_vpr_find_free_region_in_range(vpr, 0, vpr->num_pages - 1, + num_pages, align); +} + +static int tegra_vpr_find_free_region_clustered(struct tegra_vpr *vpr, + unsigned int num_pages, + unsigned int align) +{ + unsigned int target, first, last; + int pageno; + + /* + * If there are no allocations, abort the clustered allocation scheme + * and use the generic allocation scheme instead. + */ + if (vpr->first > vpr->last) + return -ENOSPC; + + /* + * First, try to allocate within the currently allocated region. This + * keeps allocations tightly packed and minimizes the VPR size needed. + */ + pageno =3D tegra_vpr_find_free_region_in_range(vpr, vpr->first, + vpr->last + 1, num_pages, + align); + if (pageno >=3D 0) + return pageno; + + /* + * If not enough free space exists within the currently allocated + * region, check to see if the allocation fits anywhere within the + * active region, avoiding the need to resize the VPR. + */ + if (tegra_vpr_get_active_range(vpr, &first, &last)) { + pageno =3D tegra_vpr_find_free_region_in_range(vpr, first, last, + num_pages, align); + if (pageno >=3D 0) + return pageno; + } + + /* + * If not enough free space exists within the currently active region, + * try to allocate adjacent to it to grow it contiguously and ensure + * optimal packing. + */ + + /* + * Calculate where the allocation should start to end right at the + * first allocated page, with proper alignment. + */ + if (vpr->first >=3D num_pages) { + target =3D ALIGN_DOWN(vpr->first - num_pages, align); + + if (!bitmap_allocate(vpr->bitmap, target, num_pages)) + return target; + } + + /* Try after the last allocation */ + target =3D ALIGN(vpr->last + 1, align); + + if (target + num_pages <=3D vpr->num_pages && + !bitmap_allocate(vpr->bitmap, target, num_pages)) + return target; + + /* + * Couldn't allocate at the ideal adjacent position, search for any + * available space before the first allocated page. + */ + pageno =3D tegra_vpr_find_free_region_in_range(vpr, 0, vpr->first, + num_pages, align); + if (pageno >=3D 0) + return pageno; + + /* + * Couldn't allocate at the ideal adjacent position, search + * for any available space after the last allocated page. + */ + pageno =3D tegra_vpr_find_free_region_in_range(vpr, vpr->last + 1, + vpr->num_pages, num_pages, + align); + if (pageno >=3D 0) + return pageno; + + return -ENOSPC; +} + +/* + * Find a free region, preferring locations near existing allocations to + * minimize VPR fragmentation. The allocation strategy is to first allocate + * within or adjacent to the existing region to keep allocations clustered. + * Otherwise fall back to a generic allocation using the first available + * space. + * + * This approach focuses on page-level allocation first, then the chunk + * system determines which chunks need to be activated based on where the + * pages ended up. + */ +static int tegra_vpr_allocate_region(struct tegra_vpr *vpr, + unsigned int num_pages, + unsigned int align) +{ + int pageno; + + /* + * For non-resizable VPR (no chunks), use simple first-fit allocation. + * Clustering optimization is only beneficial for resizable VPR where + * keeping allocations together minimizes the active VPR size. + */ + if (!vpr->resizable) + return tegra_vpr_find_free_region(vpr, num_pages, align); + + /* + * Check if there are any existing allocations in the bitmap. If so, + * try to allocate near them to minimize fragmentation. + */ + pageno =3D tegra_vpr_find_free_region_clustered(vpr, num_pages, align); + if (pageno >=3D 0) + return pageno; + + /* + * If there are no existing allocations, or no space adjacent to them, + * fall back to the first available space anywhere in the VPR. + */ + pageno =3D tegra_vpr_find_free_region(vpr, num_pages, align); + if (pageno >=3D 0) + return pageno; + + return -ENOSPC; +} + +static struct tegra_vpr_buffer * +tegra_vpr_buffer_allocate(struct tegra_vpr *vpr, size_t size) +{ + unsigned int num_pages =3D size >> PAGE_SHIFT; + unsigned int order =3D get_order(size); + struct tegra_vpr_buffer *buffer; + unsigned long first, last; + int pageno, err; + + /* + * Quick sanity check that we're not trying to allocate a buffer that + * has no chance of fitting into the VPR. + */ + if (size > vpr->size) + return ERR_PTR(-EINVAL); + + /* + * "order" defines the alignment and size, so this may result in + * fragmented memory depending on the allocation patterns. However, + * since this is used primarily for video frames, it is expected that + * a number of buffers of the same size will be allocated, so + * fragmentation should be negligible. + */ + pageno =3D tegra_vpr_allocate_region(vpr, num_pages, 1); + if (pageno < 0) + return ERR_PTR(pageno); + + first =3D find_first_bit(vpr->bitmap, vpr->num_pages); + last =3D find_last_bit(vpr->bitmap, vpr->num_pages); + + buffer =3D kzalloc_obj(*buffer, GFP_KERNEL); + if (!buffer) { + err =3D -ENOMEM; + goto release; + } + + INIT_LIST_HEAD(&buffer->attachments); + INIT_LIST_HEAD(&buffer->list); + mutex_init(&buffer->lock); + buffer->start =3D vpr->base + (pageno << PAGE_SHIFT); + buffer->limit =3D buffer->start + size; + buffer->size =3D size; + buffer->num_pages =3D num_pages; + buffer->pageno =3D pageno; + buffer->order =3D order; + + /* track which chunks this buffer overlaps */ + if (vpr->resizable) { + unsigned int limit =3D buffer->pageno + buffer->num_pages; + pgoff_t i; + + /* + * Memory is backed by struct page, so track which ones we + * use. + */ + buffer->pages =3D kvmalloc_array(buffer->num_pages, + sizeof(*buffer->pages), + GFP_KERNEL); + if (!buffer->pages) { + err =3D -ENOMEM; + goto free; + } + + for (i =3D 0; i < buffer->num_pages; i++) + buffer->pages[i] =3D &vpr->start_page[pageno + i]; + + for (i =3D 0; i < vpr->num_chunks; i++) { + struct tegra_vpr_chunk *chunk =3D &vpr->chunks[i]; + + if (tegra_vpr_chunk_overlaps(chunk, pageno, limit)) + set_bit(i, buffer->chunks); + } + + /* activate chunks if necessary */ + err =3D tegra_vpr_activate_chunks(vpr, buffer); + if (err < 0) { + kfree(buffer->pages); + goto free; + } + + /* track first and last allocated pages */ + if (buffer->pageno < vpr->first) + vpr->first =3D buffer->pageno; + + if (limit - 1 > vpr->last) + vpr->last =3D limit - 1; + } + + return buffer; + +free: + kfree(buffer); +release: + bitmap_clear(vpr->bitmap, pageno, num_pages); + return ERR_PTR(err); +} + +static void tegra_vpr_buffer_release(struct tegra_vpr_buffer *buffer) +{ + struct tegra_vpr *vpr =3D buffer->vpr; + struct tegra_vpr_buffer *entry; + unsigned int i; + + /* + * Decrement buffer count for each overlapping chunk. Note that chunks + * are not deactivated here yet, that's done in tegra_vpr_recycle() + * instead. + */ + for_each_set_bit(i, buffer->chunks, vpr->num_chunks) { + if (!WARN_ON(vpr->chunks[i].num_buffers =3D=3D 0)) + vpr->chunks[i].num_buffers--; + } + + /* track first and last allocated pages */ + if (list_is_first(&buffer->list, &vpr->buffers) && + list_is_last(&buffer->list, &vpr->buffers)) { + /* if there are no remaining buffers after this, reset */ + vpr->first =3D ~0U; + vpr->last =3D 0U; + } else if (list_is_first(&buffer->list, &vpr->buffers)) { + entry =3D list_next_entry(buffer, list); + vpr->first =3D entry->pageno; + } else if (list_is_last(&buffer->list, &vpr->buffers)) { + entry =3D list_prev_entry(buffer, list); + vpr->last =3D entry->pageno + entry->num_pages - 1; + } + + bitmap_clear(vpr->bitmap, buffer->pageno, buffer->num_pages); + list_del(&buffer->list); + kfree(buffer->pages); + kfree(buffer); +} + +static int tegra_vpr_attach(struct dma_buf *buf, + struct dma_buf_attachment *attachment) +{ + struct tegra_vpr_buffer *buffer =3D buf->priv; + struct tegra_vpr_attachment *attach; + int err; + + attach =3D kzalloc_obj(*attach, GFP_KERNEL); + if (!attach) + return -ENOMEM; + + /* + * For resizable VPR, the memory is backed by struct page, so we can + * use the convenient helper to create the SG table. + */ + if (buffer->pages) { + err =3D sg_alloc_table_from_pages(&attach->sgt, buffer->pages, + buffer->num_pages, 0, + buffer->size, GFP_KERNEL); + if (err < 0) + goto free; + } else { + if (sg_alloc_table(&attach->sgt, 1, GFP_KERNEL)) { + err =3D -ENOMEM; + goto free; + } + + sg_set_page(attach->sgt.sgl, NULL, buffer->size, 0); + sg_dma_address(attach->sgt.sgl) =3D buffer->start; + sg_dma_len(attach->sgt.sgl) =3D buffer->size; + } + + attach->dev =3D attachment->dev; + INIT_LIST_HEAD(&attach->list); + attachment->priv =3D attach; + + mutex_lock(&buffer->lock); + list_add(&attach->list, &buffer->attachments); + mutex_unlock(&buffer->lock); + + return 0; + +free: + kfree(attach); + return err; +} + +static void tegra_vpr_detach(struct dma_buf *buf, + struct dma_buf_attachment *attachment) +{ + struct tegra_vpr_buffer *buffer =3D buf->priv; + struct tegra_vpr_attachment *attach =3D attachment->priv; + + mutex_lock(&buffer->lock); + list_del(&attach->list); + mutex_unlock(&buffer->lock); + + sg_free_table(&attach->sgt); + kfree(attach); +} + +static struct sg_table * +tegra_vpr_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct tegra_vpr_attachment *attach =3D attachment->priv; + struct sg_table *sgt =3D &attach->sgt; + int err; + + err =3D dma_map_sgtable(attachment->dev, sgt, direction, + DMA_ATTR_SKIP_CPU_SYNC); + if (err < 0) + return ERR_PTR(err); + + return sgt; +} + +static void tegra_vpr_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *sgt, + enum dma_data_direction direction) +{ + dma_unmap_sgtable(attachment->dev, sgt, direction, + DMA_ATTR_SKIP_CPU_SYNC); +} + +static void tegra_vpr_recycle(struct tegra_vpr *vpr) +{ + DECLARE_BITMAP(dirty, vpr->num_chunks); + unsigned int i; + int err; + + if (!vpr->resizable) + return; + + bitmap_zero(dirty, vpr->num_chunks); + + /* + * Deactivate any unused chunks from the bottom... + */ + for (i =3D 0; i < vpr->num_chunks; i++) { + struct tegra_vpr_chunk *chunk =3D &vpr->chunks[i]; + + if (!chunk->active) + continue; + + if (chunk->num_buffers > 0) + break; + + err =3D tegra_vpr_chunk_deactivate(chunk); + if (err < 0) { + pr_err("failed to deactivate chunk #%u: %d\n", i, err); + goto activate; + } else { + clear_bit(i, vpr->active); + set_bit(i, dirty); + } + } + + /* + * ... and the top. + */ + for (i =3D 0; i < vpr->num_chunks; i++) { + unsigned int index =3D vpr->num_chunks - i - 1; + struct tegra_vpr_chunk *chunk =3D &vpr->chunks[index]; + + if (!chunk->active) + continue; + + if (chunk->num_buffers > 0) + break; + + err =3D tegra_vpr_chunk_deactivate(chunk); + if (err < 0) { + pr_err("failed to deactivate chunk #%u: %d\n", index, + err); + goto activate; + } else { + clear_bit(index, vpr->active); + set_bit(index, dirty); + } + } + + if (!bitmap_empty(dirty, vpr->num_chunks)) { + err =3D tegra_vpr_resize(vpr); + if (err < 0) { + pr_err("failed to shrink VPR: %d\n", err); + goto activate; + } + } + + /* release the CMA memory associated with deactivated chunks */ + for_each_set_bit(i, dirty, vpr->num_chunks) + tegra_vpr_chunk_release(&vpr->chunks[i]); + + return; + +activate: + for_each_set_bit(i, dirty, vpr->num_chunks) { + err =3D tegra_vpr_chunk_activate(&vpr->chunks[i]); + if (WARN_ON(err < 0)) + pr_err("failed to activate chunk #%u: %d\n", i, err); + + /* + * This may not be fully activated at this point, but we need + * to keep track of it anyway to make sure the CMA region can + * eventually be released. The WARN_ON above tells us when it + * happens: here be dragons. + */ + set_bit(i, vpr->active); + } +} + +static void tegra_vpr_release(struct dma_buf *buf) +{ + struct tegra_vpr_buffer *buffer =3D buf->priv; + struct tegra_vpr *vpr =3D buffer->vpr; + + mutex_lock(&vpr->lock); + + tegra_vpr_buffer_release(buffer); + tegra_vpr_recycle(vpr); + + mutex_unlock(&vpr->lock); +} + +/* + * Prohibit userspace mapping because the CPU cannot access this memory + * anyway. + */ +static int tegra_vpr_begin_cpu_access(struct dma_buf *buf, + enum dma_data_direction direction) +{ + return -EPERM; +} + +static int tegra_vpr_end_cpu_access(struct dma_buf *buf, + enum dma_data_direction direction) +{ + return -EPERM; +} + +static int tegra_vpr_mmap(struct dma_buf *buf, struct vm_area_struct *vma) +{ + return -EPERM; +} + +static const struct dma_buf_ops tegra_vpr_buf_ops =3D { + .attach =3D tegra_vpr_attach, + .detach =3D tegra_vpr_detach, + .map_dma_buf =3D tegra_vpr_map_dma_buf, + .unmap_dma_buf =3D tegra_vpr_unmap_dma_buf, + .release =3D tegra_vpr_release, + .begin_cpu_access =3D tegra_vpr_begin_cpu_access, + .end_cpu_access =3D tegra_vpr_end_cpu_access, + .mmap =3D tegra_vpr_mmap, +}; + +static struct dma_buf *tegra_vpr_allocate(struct dma_heap *heap, + unsigned long len, u32 fd_flags, + u64 heap_flags) +{ + struct tegra_vpr *vpr =3D dma_heap_get_drvdata(heap); + struct tegra_vpr_buffer *buffer, *entry; + size_t size =3D ALIGN(len, vpr->align); + DEFINE_DMA_BUF_EXPORT_INFO(export); + struct dma_buf *buf; + + mutex_lock(&vpr->lock); + + buffer =3D tegra_vpr_buffer_allocate(vpr, size); + if (IS_ERR(buffer)) { + mutex_unlock(&vpr->lock); + return ERR_CAST(buffer); + } + + /* insert in the correct order */ + if (!list_empty(&vpr->buffers)) { + list_for_each_entry(entry, &vpr->buffers, list) { + if (buffer->pageno < entry->pageno) { + list_add_tail(&buffer->list, &entry->list); + break; + } + } + } + + if (list_empty(&buffer->list)) + list_add_tail(&buffer->list, &vpr->buffers); + + buffer->vpr =3D vpr; + + /* + * If a valid buffer was allocated, wrap it in a dma_buf + * and return it. + */ + export.exp_name =3D dma_heap_get_name(heap); + export.ops =3D &tegra_vpr_buf_ops; + export.size =3D buffer->size; + export.flags =3D fd_flags; + export.priv =3D buffer; + + buf =3D dma_buf_export(&export); + if (IS_ERR(buf)) { + tegra_vpr_buffer_release(buffer); + tegra_vpr_recycle(vpr); + } + + mutex_unlock(&vpr->lock); + return buf; +} + +static void tegra_vpr_debugfs_show_buffers(struct tegra_vpr *vpr, + struct seq_file *s) +{ + struct tegra_vpr_buffer *buffer; + char buf[16]; + + mutex_lock(&vpr->lock); + + list_for_each_entry(buffer, &vpr->buffers, list) { + string_get_size(buffer->size, 1, STRING_UNITS_2, buf, + sizeof(buf)); + seq_printf(s, " %pap-%pap (%s)\n", &buffer->start, + &buffer->limit, buf); + } + + mutex_unlock(&vpr->lock); +} + +static void tegra_vpr_debugfs_show_chunks(struct tegra_vpr *vpr, + struct seq_file *s) +{ + struct tegra_vpr_buffer *buffer; + unsigned int i; + char buf[16]; + + for (i =3D 0; i < vpr->num_chunks; i++) { + const struct tegra_vpr_chunk *chunk =3D &vpr->chunks[i]; + + string_get_size(chunk->size, 1, STRING_UNITS_2, buf, + sizeof(buf)); + seq_printf(s, " %pap-%pap (%s) (%s, %u buffers)\n", + &chunk->start, &chunk->limit, buf, + chunk->active ? "active" : "inactive", + chunk->num_buffers); + } + + list_for_each_entry(buffer, &vpr->buffers, list) { + string_get_size(buffer->size, 1, STRING_UNITS_2, buf, + sizeof(buf)); + seq_printf(s, "%pap-%pap (%s, chunks: %*pbl)\n", + &buffer->start, &buffer->limit, buf, + vpr->num_chunks, buffer->chunks); + } +} + +static int tegra_vpr_debugfs_show(struct seq_file *s, struct dma_heap *hea= p) +{ + struct tegra_vpr *vpr =3D dma_heap_get_drvdata(heap); + phys_addr_t limit =3D vpr->base + vpr->size; + char buf[16]; + + string_get_size(vpr->size, 1, STRING_UNITS_2, buf, sizeof(buf)); + seq_printf(s, "%pap-%pap (%s)\n", &vpr->base, &limit, buf); + + if (!vpr->resizable) + tegra_vpr_debugfs_show_buffers(vpr, s); + else + tegra_vpr_debugfs_show_chunks(vpr, s); + + return 0; +} + +static const struct dma_heap_ops tegra_vpr_heap_ops =3D { + .allocate =3D tegra_vpr_allocate, + .show =3D tegra_vpr_debugfs_show, +}; + +static int tegra_vpr_setup_chunks(struct tegra_vpr *vpr, const char *name) +{ + phys_addr_t start, limit; + unsigned int order, i =3D 0; + size_t max_size; + int err; + + /* Memory is backed by struct page, so track the first one. */ + vpr->start_page =3D phys_to_page(vpr->base); + + /* This seems a reasonable value, so hard-code it for now. */ + vpr->num_chunks =3D 4; + + vpr->chunks =3D kzalloc_objs(*vpr->chunks, vpr->num_chunks); + if (!vpr->chunks) + return -ENOMEM; + + vpr->active =3D bitmap_zalloc(vpr->num_chunks, GFP_KERNEL); + if (!vpr->active) { + err =3D -ENOMEM; + goto free; + } + + max_size =3D PAGE_SIZE << (get_order(vpr->size) - ilog2(vpr->num_chunks)); + order =3D get_order(vpr->align); + + /* + * Allocate CMA areas for VPR. All areas will be roughtly the same + * size, with the last area taking up the rest. + */ + start =3D vpr->base; + limit =3D vpr->base + vpr->size; + + pr_debug("VPR: %pap-%pap (%lu pages, %u chunks, %lu MiB)\n", &start, + &limit, vpr->num_pages, vpr->num_chunks, + (unsigned long)vpr->size / 1024 / 1024); + + for (i =3D 0; i < vpr->num_chunks; i++) { + size_t size =3D limit - start; + phys_addr_t end; + + size =3D min_t(size_t, size, max_size); + end =3D start + size - 1; + + err =3D tegra_vpr_chunk_init(vpr, &vpr->chunks[i], start, size, + order, name); + if (err < 0) { + pr_err("failed to create VPR chunk: %d\n", err); + goto free; + } + + pr_debug(" %2u: %pap-%pap (%lu MiB)\n", i, &start, &end, + size / 1024 / 1024); + start +=3D size; + } + + vpr->first =3D ~0U; + vpr->last =3D 0U; + + return 0; + +free: + while (i--) + tegra_vpr_chunk_free(&vpr->chunks[i]); + + kfree(vpr->active); + kfree(vpr->chunks); + return err; +} + +static void tegra_vpr_free_chunks(struct tegra_vpr *vpr) +{ + unsigned int i; + + for (i =3D 0; i < vpr->num_chunks; i++) + tegra_vpr_chunk_free(&vpr->chunks[i]); + + kfree(vpr->chunks); +} + +static int tegra_vpr_setup_static(struct tegra_vpr *vpr) +{ + phys_addr_t start, limit; + + start =3D vpr->base; + limit =3D vpr->base + vpr->size; + + pr_debug("VPR: %pap-%pap (%lu pages, %lu MiB)\n", &start, &limit, + vpr->num_pages, (unsigned long)vpr->size / 1024 / 1024); + + return 0; +} + +static int tegra_vpr_add_heap(struct reserved_mem *rmem, + struct device_node *np) +{ + struct dma_heap_export_info info =3D {}; + unsigned long first, last; + struct dma_heap *heap; + struct tegra_vpr *vpr; + int err; + + vpr =3D kzalloc_obj(*vpr, GFP_KERNEL); + if (!vpr) + return -ENOMEM; + + INIT_LIST_HEAD(&vpr->list); + INIT_LIST_HEAD(&vpr->buffers); + INIT_LIST_HEAD(&vpr->devices); + mutex_init(&vpr->lock); + + vpr->resizable =3D !of_property_read_bool(np, "no-map"); + vpr->dev_node =3D of_node_get(np); + vpr->align =3D PAGE_SIZE; + vpr->base =3D rmem->base; + vpr->size =3D rmem->size; + vpr->num_pages =3D vpr->size >> PAGE_SHIFT; + vpr->nid =3D of_node_to_nid(np); + vpr->cma =3D rmem->priv; + + vpr->bitmap =3D bitmap_zalloc(vpr->num_pages, GFP_KERNEL); + if (!vpr->bitmap) { + err =3D -ENOMEM; + goto free; + } + + first =3D find_first_bit(vpr->bitmap, vpr->num_pages); + last =3D find_last_bit(vpr->bitmap, vpr->num_pages); + + if (vpr->resizable) + err =3D tegra_vpr_setup_chunks(vpr, rmem->name); + else + err =3D tegra_vpr_setup_static(vpr); + + if (err < 0) + goto free; + + info.name =3D vpr->dev_node->name; + info.ops =3D &tegra_vpr_heap_ops; + info.priv =3D vpr; + + heap =3D dma_heap_add(&info); + if (IS_ERR(heap)) { + err =3D PTR_ERR(heap); + goto cleanup; + } + + mutex_lock(&vpr_lock); + list_add_tail(&vpr->list, &vpr_list); + mutex_unlock(&vpr_lock); + + return 0; + +cleanup: + if (vpr->resizable) + tegra_vpr_free_chunks(vpr); +free: + bitmap_free(vpr->bitmap); + kfree(vpr); + return err; +} + +static int tegra_vpr_init(void) +{ + const char *compatible =3D "nvidia,tegra-video-protection-region"; + struct device_node *parent; + struct reserved_mem *rmem; + int err; + + parent =3D of_find_node_by_path("/reserved-memory"); + if (!parent) + return 0; + + for_each_child_of_node_scoped(parent, child) { + if (!of_device_is_compatible(child, compatible)) + continue; + + rmem =3D of_reserved_mem_lookup(child); + if (!rmem) + continue; + + err =3D tegra_vpr_add_heap(rmem, child); + if (err < 0) + pr_err("failed to add VPR heap for %pOF: %d\n", child, + err); + + /* only a single VPR heap is supported */ + break; + } + + of_node_put(parent); + return 0; +} +module_init(tegra_vpr_init); + +static int __init tegra_vpr_node_init(unsigned long offset, + struct reserved_mem *rmem) +{ + struct cma *cma; + int err; + + if (!IS_ALIGNED(rmem->base, SZ_1M)) { + pr_err("%s: base is not aligned to 1 MiB\n", rmem->name); + return -EINVAL; + } + + if (!IS_ALIGNED(rmem->size, SZ_1M)) { + pr_err("%s: size is not aligned to 1 MiB\n", rmem->name); + return -EINVAL; + } + + err =3D cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, + &cma); + if (err < 0) { + pr_err("%s: failed to initialize CMA: %d\n", __func__, err); + return err; + } + + rmem->priv =3D cma; + + return 0; +} + +static struct tegra_vpr *tegra_vpr_lookup(struct cma *cma) +{ + struct tegra_vpr *vpr; + + mutex_lock(&vpr_lock); + + list_for_each_entry(vpr, &vpr_list, list) { + if (vpr->cma =3D=3D cma) { + mutex_unlock(&vpr_lock); + return vpr; + } + } + + mutex_unlock(&vpr_lock); + + return ERR_PTR(-EPROBE_DEFER); +} + +static int tegra_vpr_device_init(struct reserved_mem *rmem, struct device = *dev) +{ + const struct dev_pm_ops *pm =3D dev->driver->pm; + struct tegra_vpr_device *node; + struct cma *cma =3D rmem->priv; + struct tegra_vpr *vpr; + + vpr =3D tegra_vpr_lookup(cma); + if (IS_ERR(vpr)) + return PTR_ERR(vpr); + + if (!pm || !pm->freeze || !pm->thaw) + return -EINVAL; + + node =3D kzalloc_obj(*node, GFP_KERNEL); + if (!node) + return -ENOMEM; + + INIT_LIST_HEAD(&node->node); + node->dev =3D dev; + + mutex_lock(&vpr->lock); + list_add_tail(&node->node, &vpr->devices); + mutex_unlock(&vpr->lock); + + return 0; +} + +static void tegra_vpr_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + struct tegra_vpr_device *node, *tmp; + struct cma *cma =3D rmem->priv; + struct tegra_vpr *vpr; + + vpr =3D tegra_vpr_lookup(cma); + if (IS_ERR(vpr)) { + dev_WARN(dev, "failed to find VPR for CMA '%s'\n", + cma_get_name(cma)); + return; + } + + mutex_lock(&vpr->lock); + + list_for_each_entry_safe(node, tmp, &vpr->devices, node) { + if (node->dev =3D=3D dev) { + list_del(&node->node); + kfree(node); + } + } + + mutex_unlock(&vpr->lock); +} + +static const struct reserved_mem_ops tegra_vpr_rmem_ops =3D { + .node_init =3D tegra_vpr_node_init, + .device_init =3D tegra_vpr_device_init, + .device_release =3D tegra_vpr_device_release, +}; + +RESERVEDMEM_OF_DECLARE(tegra_vpr, "nvidia,tegra-video-protection-region", + &tegra_vpr_rmem_ops); + +MODULE_DESCRIPTION("NVIDIA Tegra Video-Protection-Region DMA-BUF heap driv= er"); +MODULE_LICENSE("GPL"); diff --git a/include/trace/events/tegra_vpr.h b/include/trace/events/tegra_= vpr.h new file mode 100644 index 000000000000..f8ceb17679fe --- /dev/null +++ b/include/trace/events/tegra_vpr.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#if !defined(_TRACE_TEGRA_VPR_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_TEGRA_VPR_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM tegra_vpr + +#include + +TRACE_EVENT(tegra_vpr_chunk_activate, + TP_PROTO(phys_addr_t start, phys_addr_t limit), + TP_ARGS(start, limit), + TP_STRUCT__entry( + __field(phys_addr_t, start) + __field(phys_addr_t, limit) + ), + TP_fast_assign( + __entry->start =3D start; + __entry->limit =3D limit; + ), + TP_printk("%pap-%pap", &__entry->start, + &__entry->limit) +); + +TRACE_EVENT(tegra_vpr_chunk_deactivate, + TP_PROTO(phys_addr_t start, phys_addr_t limit), + TP_ARGS(start, limit), + TP_STRUCT__entry( + __field(phys_addr_t, start) + __field(phys_addr_t, limit) + ), + TP_fast_assign( + __entry->start =3D start; + __entry->limit =3D limit; + ), + TP_printk("%pap-%pap", &__entry->start, + &__entry->limit) +); + +TRACE_EVENT(tegra_vpr_set, + TP_PROTO(phys_addr_t base, phys_addr_t size), + TP_ARGS(base, size), + TP_STRUCT__entry( + __field(phys_addr_t, start) + __field(phys_addr_t, limit) + ), + TP_fast_assign( + __entry->start =3D base; + __entry->limit =3D base + size; + ), + TP_printk("%pap-%pap", &__entry->start, &__entry->limit) +); + +#endif /* _TRACE_TEGRA_VPR_H */ + +#include --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1BD9C485CEC; Fri, 14 Aug 2026 15:29:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721396; cv=none; b=e1TWMMSrT81SCw+lqttJt/oUbP//JVAWeK3L1IjqrJS7PGjepHXcATFenfcp6qron68wNK6l/8nQWdKM9fqIzWeY0v19BsCDMm0KXgFZVY6S3TJaA5vbDB616Jrn0e3OK7HtnPlxvJilC9VYS2d61UCBvANM/NetF+wRW/nK9vE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721396; c=relaxed/simple; bh=5EtoJr2asw/bScq7iQsbmEz9QkSjIOA5+gLk9QdMxBE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Soo/pNSRGNNM6SJIabKJdUhgHDJnqoUSvHlE18qwTzSc6z0Kg1jLQA2e+R7lEfV7nH7bI79mHUQ4EbqJAY48HtZ8REEEcu0erl5J8zrCmPFGNOSJysko9oWYnGQ960PwW+vVwbzYq/T4uDP5oXTk/TdOm4UdtTsBFIt0XzzPii4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NcMsbplE; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NcMsbplE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 190991F00A3D; Fri, 14 Aug 2026 15:29:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721394; bh=3Jc01ta292IyzRQJ7S0gkfePZTtvrNXCh0bWGk/zJv0=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=NcMsbplEtDdQm6kh/SGOLa0/RJQNEWfL/2BfcjnGXSUNBYosAjU0UjnY9lqbWaoJ9 Nie8FAah4yhGJ55myjaV0rn9kAUDHZlcnnA+8c5Ga8uNtWAPWYt/+gaPFZvtFNJmg+ s2FlVihIsR7NcKRwbaa2oktybdQRP+j1QOkgPiNqzBx8fXZA15gdbWHnJ9QBSTzLLX 2CV2SXUi9O995eCjstVnkSWEbxVghqpUOFlq58CjSA4RzlNCqWradz6dV6lzuwzLE3 D7Q+CFhySsr0Na19Z8tc/Rb4CPGtlNnqorlvDV4iVdM7N22Ei7ksrkpadYIYCCUZa8 TP7eYcE7F23Ag== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:16 +0200 Subject: [PATCH v5 08/10] arm64: tegra: Add VPR placeholder node on Tegra234 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-8-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=2272; i=treding@nvidia.com; h=from:subject:message-id; bh=tluD4wsCTEuKp0Tp27V1iO02LeJ7xPXs3NTBGtUc+lo=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRYDbNpqpdmgbeamv4SdSlpqySEBNbb9exns Tov5wvAxDaJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80WAAKCRDdI6zXfz6z oWaID/0QBemia5v7XUxUcYFPeszOyYomA7N68168MqyiTj7lE0A+c9LcFnN5wTRYmZjQ3lubFAT F2HaLwt+kPeF/rzJ8ZkcCgRjp4ZJ+jhGFu+IkvpzRy/idEkblTNtJiSVFRxmNjv1VfbeFSHaiG7 Bp8voh2mGvgzmRKPeSasjQeBZkcuhByhnkjeirZ2Z7bryipcJKMcGc2LykMBFp1I/LhMQugP8mp MmUexP9jDjXpoSc6lpg8hC0MyZ95YAwh8cv/dztaihtWMEP8i+zfe14J2jhGA+DuxxNStXOVSSd okTJkF3HU2vgfHQ9ffWlLUpBWuLHdV5++fA9pLVApYRlfM2p4eN9F0RuOvbJMTri5w2OhlwoFs9 yBn8zjkPEdjbeEr3dJr8GNBsdBd/2E+646SwOz2H/FymQfdcO2KZ1fCNqoY6zcxJm29FO989zw9 WsnYje5s5jmPWh4vTbHXKbsGhg6Nrij/0aIpuQfrKEWH4HgVECEezUGJvGV7GGfcWb8l/w8oKjm FFczQ7Y6jWGGk3R68xW7D//Bq15sv4ee0TV7zgIiywdgvrhMK5PkD7+htoOPyb/7O2Ch09ZZWOu Pfs9PIILCsG6PBXjil+eqWs1zcmONmwP+iRo7XXXIl3db+vvHbSZcivk5Oi67d6NvBIouAaEx0o WkPiMhhZYK2UFTw== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding This node contains two sets of properties, one for the case where the VPR is resizable (in which case the VPR region will be dynamically allocated at boot time) and another case where the VPR is fixed in size and initialized by early firmware. The firmware running on the device is responsible for updating the node with the real physical address for the fixed VPR case and remove the properties needed only for resizable VPR. Similarly, if the VPR is resizable, the firmware should remove the "reg" property since it is no longer needed. Signed-off-by: Thierry Reding --- Changes in v3: - comment out fixed VPR properties, assume resizable by default - rename node to "protected" --- arch/arm64/boot/dts/nvidia/tegra234.dtsi | 39 ++++++++++++++++++++++++++++= ++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts= /nvidia/tegra234.dtsi index 5e29316a4d75..6c4739efc8a5 100644 --- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi @@ -29,6 +29,45 @@ aliases { i2c8 =3D &dp_aux_ch3_i2c; }; =20 + reserved-memory { + #address-cells =3D <2>; + #size-cells =3D <2>; + ranges; + + vpr: protected { + compatible =3D "nvidia,tegra-video-protection-region"; + status =3D "disabled"; + + /* + * Two variants exist for this. For fixed VPR, the + * firmware is supposed to update the "reg" property + * with the fixed memory region configured as VPR. + * + * For resizable VPR we don't care about the exact + * address and instead want a reserved region to be + * allocated with a certain size and alignment at + * boot time. + * + * The below assumes resizable VPR by default. If the + * firmwares sets up fixed VPR, it is responsible for + * adding the missing "reg" property, removing any of + * the unused properties, as well as adding a unit- + * address matching the "reg" property. + */ + + /* fixed VPR */ + /* + reg =3D <0x0 0x0 0x0 0x0>; + no-map; + */ + + /* resizable VPR */ + size =3D <0x0 0x70000000>; + alignment =3D <0x0 0x100000>; + reusable; + }; + }; + bus@0 { compatible =3D "simple-bus"; =20 --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B0F30484249; Fri, 14 Aug 2026 15:29:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721399; cv=none; b=kgWkrMCnxiqFd/Xf9uPi/TFqNnPuucI1X2Hm2roqlCEOEZ4r7/DTmeNS0jXlG1ADfU+FRZrgWqrhopXfD48lZX1xzbcF+2e0Lb8Zv07YrmusuMI3emzOjeT99AzgHUIzuQcBSP+k3vY30xagyTU29ryxg96PCV26mlK5wntzHpA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721399; c=relaxed/simple; bh=M/R66TK9cvXJNZGsNZJnMU04s2BAQALQxYjf0kzv07A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EMv/oKvVaHVCDlw7DyYxH9aOFcx8O3QOdNhOSxDTupxYJu5W4GFTuanZMKB1d9C0yQSuevcTcmzxWUNgbS+AjL9x2nkuXfko0R4hFhZ2wDKsmaqB1iY+VOrjevUGJLtoCpiVF3dhvs6E07x5ubA1ScRCbUcJhQWullVgCAbnXnY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TlY9dOe/; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TlY9dOe/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DA3671F000E9; Fri, 14 Aug 2026 15:29:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721397; bh=YsqfU4rnOxCjbdNELUfPy2EP2mOE10vhuCcFu2B7Ivw=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=TlY9dOe/m49Es17ojXqtIC6JsPPLhB51fuiigq9mhO0OsfqU/dpS8ol9VSMirZnys N+Sz7Y0JvYdHmVXeGhp8lyOGBKXLCZRDGKUGk5Af1VVt5A0DxxrqHZrIW1wv7HVEuI Gk+W6MGpvoBmb3bQILgXFn225Y9gykLhrAfhdMmbi+FyWEntwqfXVZkEOkp7M44puc DdILQj4CoIG67RY/8F1SNui1WxkIqGgZT9PlkkXmIAnN0eqFymVnrX5PDfHaPLYabi jDEZUsxAYgC7oqJaLzWt+C0vDZoz/Gpks+B5Y/ifhVblSniSS/eCj9O87aYsKWHVt6 c94JDdp63Kh4A== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:17 +0200 Subject: [PATCH v5 09/10] arm64: tegra: Hook up VPR to host1x Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-9-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1002; i=treding@nvidia.com; h=from:subject:message-id; bh=uOEc0ecGZ8h9g47cFlkUo3cheaRQXqI5mvM+m7jx2j8=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRYQ9J+7I4U2eaXmCOV49EwtyF4cmPzXhSyC Tq+2quY1HaJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80WAAKCRDdI6zXfz6z oU/AD/0XRytJsEu68Ff0PfHtnK+eBBRHrioM9YqCgL5aBA80Zw/VnVUReuBPZZ6wyk2zAETMZGU I06nPkJi6TA/NwJwuc2pygr5F7fDVmL+rsO38ovw2JGgCdiCOciqpsd9cDqquDI59a5dwo1VULN LhvF8edxPjVFQlcCRihSuMvlOuhwngvYJ2or6ng0CLh4w4xrPsFCPTG9eh0hUvQQIdMeyIroGug K6+q4Y/za6Isw3zXh++Yb7elZScIp3dPC96xEpF67MVqJ5Zr+Hdt2BoC1OUWAX2vCNXn+ezHxLW CnjP4Y5h6zOC7WNnucPZGvecau6mMIU3EEXqKy/OehY0OFZujo6EsFJsopFibt1OIZ5L1oXcq8N TwU08UiHSX7OCL7SpcZ8vIG/093IzXWnkkZL8sfsc1Ygg1QL2oervYhf+zsLFMlHu7FMt4UqouL hNmstA9OD+5jBqNaSQ112uV2CINjMclaevNLLjm48+z6m363cfrD102Ybu9PjEibOoT/psH5Am2 mLHTSjBZblYA78ADS4coEm/4O7B2/Nwu4Lv2dGanNcw5Ey1unUinkIQrexFKxH1rNu3GpEqyAGE SAy3sjcVNL3Paa25oMm2xMKJ+zD9mjY3+e/sYwrE6sW/OnXgp6X1KggP85+52DqrsX0GcezgMAk C3trgaesgMJRKPg== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding The host1x needs access to the VPR region, so make sure to reference it via the memory-region property. Signed-off-by: Thierry Reding --- arch/arm64/boot/dts/nvidia/tegra234.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts= /nvidia/tegra234.dtsi index 6c4739efc8a5..c6a5ced069e7 100644 --- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi @@ -4479,6 +4479,9 @@ vic@15340000 { interconnect-names =3D "dma-mem", "write"; iommus =3D <&smmu_niso1 TEGRA234_SID_VIC>; dma-coherent; + + memory-region =3D <&vpr>; + memory-region-names =3D "protected"; }; =20 nvdec@15480000 { @@ -4497,6 +4500,9 @@ nvdec@15480000 { iommus =3D <&smmu_niso1 TEGRA234_SID_NVDEC>; dma-coherent; =20 + memory-region =3D <&vpr>; + memory-region-names =3D "protected"; + nvidia,memory-controller =3D <&mc>; =20 /* --=20 2.55.0 From nobody Mon Sep 28 23:55:26 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BEB95486E40; Fri, 14 Aug 2026 15:30:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721403; cv=none; b=MwGIsZC45AVzZtAIMPCRT2zQuIaRH9VgYWEDbDhRW5CnRfbLU/uuEks6KWpRI68pzkbU6u2uo+MyVrgKMwPwBC3hENfyhYDRdT+zI8cOmf4dlqqONPhnq8nHnWMw2xMCrttPrKHdY49cGM+jjSYvHDCvn4bqyL1tHZxIQHIsoMY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786721403; c=relaxed/simple; bh=tl4J5nZhsTsNnoEGHzqT7X31R2+FzAdmY+JzEZBZ/wI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bLZywGSmk4W1yDFGa9LWqCUfyHED97woPrjCj45b2QuQkyZ0I8f+eZd+ftE5eCpl1uVyELOsCSnDKzExFznlN+d/+oSAOQkcB1glkqPCtDVqqD05mShwHRNAnzJigtDx34Ja3/lvgRKWG65PfmsrUmCl52WVOHLHw42dcjDuKDE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dyLKd7df; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dyLKd7df" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A70961F000E9; Fri, 14 Aug 2026 15:29:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786721400; bh=uaLT8Pt+Su2uzISlW009doIM0VJ15n6/6fL5974J+dg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=dyLKd7dfiBNnwmTsFUCJeuYgeUh8Ew4Yy3vfvAWnGGsbpXhsuQXVd8XQ9w2HaM6Zu QgBFaTPJEssOx024yYFYiy0ikk8y+yf6M2aqF58IXU4qyJA374I2BXJ7LsBV6pl8DT 5Xj+P2HKB2Pvpmjt6zEYOI340apfB0nAFJ7XkX9fme6Uj6Sja0Sl4FcAYaZnu8TMkU guyQVkgOZfVNqwCLYiPXu0ohVQDFkAnBDc0rCPHMOOb+6qmvJLpRHkLxEJw7lW+vos Ntys2s5CLDmS3/R8vkRNfeJVwr6Ss0RjKsCRj38cipYc0tgAJxcOXlAUDB4Z8VRD4s iGqg8t0wrurrw== From: Thierry Reding Date: Fri, 14 Aug 2026 17:29:18 +0200 Subject: [PATCH v5 10/10] arm64: tegra: Add VPR placeholder node on Tegra264 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260814-tegra-vpr-v5-10-71832b5d0246@nvidia.com> References: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> In-Reply-To: <20260814-tegra-vpr-v5-0-71832b5d0246@nvidia.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Sowjanya Komatineni , Luca Ceresoli , Mikko Perttunen , Yury Norov , Rasmus Villemoes , Russell King , Alexander Gordeev , Gerald Schaefer , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Sven Schnelle , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Marek Szyprowski , Robin Murphy , Sumit Semwal , Benjamin Gaignard , Brian Starkey , John Stultz , "T.J. Mercier" , =?utf-8?q?Christian_K=C3=B6nig?= , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Catalin Marinas , Will Deacon , Chun Ng Cc: Thierry Reding , devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-s390@vger.kernel.org, linux-mm@kvack.org, iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org, linux-trace-kernel@vger.kernel.org, Thierry Reding X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=2208; i=treding@nvidia.com; h=from:subject:message-id; bh=db5pktqTEHmL7nm7eEWg8RTfTXMm0eSnWFgz4562xI4=; b=owEBbQKS/ZANAwAKAd0jrNd/PrOhAcsmYgBqfzRZRCHM4P+QZFcsZdjlqbbApnEWVTk6Wm7E+ KnIdEu0AYmJAjMEAAEKAB0WIQSI6sMIAUnM98CNyJ/dI6zXfz6zoQUCan80WQAKCRDdI6zXfz6z oSXAD/9osIn6vKwbtFrpb26y/g3b9z+UjI1W3E3npab2OW3Xl4zfKOoluxB7F9krSl7aDrrKhw9 uI7kMIHw32NFU50O6kjYGE1Zi6s89gv4UeeYqNiIPtYqyU3dVS6/wt2AN2eoQgD6y5y7lgsX+a2 b+TaC+idL5S+NJxjlha1/Ax3mH0kmL/NYjMVT2F+OWOfJDFbmYtwCkXa/bnlAJaExbFvVow52w3 lKV4KUg+Q1zuwcv9wWrrkcEOElranQ1b5jO/E27+zvhIle3MhK/RkJOKCiRlFR7g1/oAIVHCYVx vLgtY9ifFDRxVuTQrWHpCJcq9q+YtSAZUiM4WjJutFgVF0fejgX7YDv23ar7NkoI7I+eiHqKv7r KznaE0HyuGIGpGExgj3QeEEMVqz7I4xibixSV+MPk2EVlm16ZcqShTUu9ZaIadCxfAS1rcRqSz1 Cz/etrRh+A2EV+V+tgDcNBE5kmN6YvTZE826o1yVVtSAVlrf7S4s/rOnwfRHTxTH7Ek3OWUkdpR kuXJlxiZ+xIKx4VQ9y03bVyg+FeLRphkOO952z6VQq5Gk13e02mBOUG2liVGPh70aWOmkoXVhtN b268m+4V1J8PieinrHxibQ6o225G8PrDeNOSGlbNKkQf6afUzpcG51yPU2vS4//Wl7rnKmgE8qO nrj9H5tdo/9uipA== X-Developer-Key: i=treding@nvidia.com; a=openpgp; fpr=88EAC3080149CCF7C08DC89FDD23ACD77F3EB3A1 From: Thierry Reding This node contains two sets of properties, one for the case where the VPR is resizable (in which case the VPR region will be dynamically allocated at boot time) and another case where the VPR is fixed in size and initialized by early firmware. The firmware running on the device is responsible for updating the node with the real physical address for the fixed VPR case and remove the properties needed only for resizable VPR. Similarly, if the VPR is resizable, the firmware should remove the "reg" property since it is no longer needed. Signed-off-by: Thierry Reding --- Changes in v3: - comment out fixed VPR properties, assume resizable by default - rename node to "protected" --- arch/arm64/boot/dts/nvidia/tegra264.dtsi | 33 ++++++++++++++++++++++++++++= ++++ 1 file changed, 33 insertions(+) diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts= /nvidia/tegra264.dtsi index 31bd29df8e46..b3a8ea64aa37 100644 --- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi @@ -24,6 +24,39 @@ shmem_bpmp: shmem@86070000 { reg =3D <0x0 0x86070000 0x0 0x2000>; no-map; }; + + vpr: protected { + compatible =3D "nvidia,tegra-video-protection-region"; + status =3D "disabled"; + + /* + * Two variants exist for this. For fixed VPR, the + * firmware is supposed to update the "reg" property + * with the fixed memory region configured as VPR. + * + * For resizable VPR we don't care about the exact + * address and instead want a reserved region to be + * allocated with a certain size and alignment at + * boot time. + * + * The below assumes resizable VPR by default. If the + * firmwares sets up fixed VPR, it is responsible for + * adding the missing "reg" property, removing any of + * the unused properties, as well as adding a unit- + * address matching the "reg" property. + */ + + /* fixed VPR */ + /* + reg =3D <0x0 0x0 0x0 0x0>; + no-map; + */ + + /* resizable VPR */ + size =3D <0x0 0x70000000>; + alignment =3D <0x0 0x100000>; + reusable; + }; }; =20 /* SYSTEM MMIO */ --=20 2.55.0