From 6e5aec9ce4f077648a63b1c8e2b0319f5ce5fb6d Mon Sep 17 00:00:00 2001 From: Ketan Patil Date: Mon, 19 Aug 2024 09:16:56 +0000 Subject: [PATCH] video: tegra: nvmap: Add new heap for VI mempool - The VI is allowed to access the whole of the Guest VM currently as it is a stage-2 SMMU device. Hence it can read and write to any memory. This may lead to breach of confidentiality and integrity. In order to restrict the VI from accessing the whole VM, a mempool is being created by HV that would restrict access to VI to just the mempool memory. - In nvmap, we have some special rules for IVM carveout like if user specify IVM carveout to allocate from, then if first IVM carveout does not have sufficient memory then nvmap tries to allocate from next IVM carveout. We don't want these rules applicable for VI mempool heap, hence only carveout initialization part would remain similar to IVM carveouts but rest of the operations would be performed normally like any other carveout. - Add DT binding doc for VI-carveout. Bug 4648721 Change-Id: Ib40415a4c80da908654c86162c1cd4b50b33ef31 Signed-off-by: Ketan Patil Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3196238 Reviewed-by: Pritesh Raithatha Reviewed-by: svc-mobile-coverity --- .../video/tegra/nvmap/nvidia,vi-carveout.yaml | 67 +++++++++++++++++ drivers/video/tegra/nvmap/nvmap_dev.h | 17 +++-- drivers/video/tegra/nvmap/nvmap_init.c | 73 ++++++++++++------- 3 files changed, 123 insertions(+), 34 deletions(-) create mode 100644 Documentation/devicetree/bindings/video/tegra/nvmap/nvidia,vi-carveout.yaml diff --git a/Documentation/devicetree/bindings/video/tegra/nvmap/nvidia,vi-carveout.yaml b/Documentation/devicetree/bindings/video/tegra/nvmap/nvidia,vi-carveout.yaml new file mode 100644 index 00000000..1110951a --- /dev/null +++ b/Documentation/devicetree/bindings/video/tegra/nvmap/nvidia,vi-carveout.yaml @@ -0,0 +1,67 @@ +# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/vi-carveout/nvidia,vi-carveout.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nvidia VI Carveout + +maintainers: + - Ketan Patil + +description: | + This schema defines the properties for the NVIDIA VI carveout (mempool) memory + node. The reference to this DT node should be added memory-region in tegra carveout + to create the VI carveout. + +select: + properties: + compatible: + minItems: 1 + maxItems: 1 + items: + enum: + - nvidia,vi_carveout + + required: + - compatible + +properties: + ivm: + description: | + A phandle to the tegra-hv node followed by the mempool id. + items: + minItems: 2 + maxItems: 2 + items: + - $ref: "/schemas/types.yaml#/definitions/phandle" + - $ref: "/schemas/types.yaml#/definitions/uint32" + + status: + description: | + The status of the carveouts node. + enum: + - okay + - disabled + +required: + - compatible + - ivm + +examples: + - | + vi-carveout { + compatible = "nvidia,vi_carveout"; + ivm = <&tegra_hv 3>; + status = "okay"; + }; diff --git a/drivers/video/tegra/nvmap/nvmap_dev.h b/drivers/video/tegra/nvmap/nvmap_dev.h index aa2ccc4f..a31e8e1a 100644 --- a/drivers/video/tegra/nvmap/nvmap_dev.h +++ b/drivers/video/tegra/nvmap/nvmap_dev.h @@ -6,15 +6,16 @@ #include -#define NVMAP_HEAP_IOVMM (1ul<<30) +#define NVMAP_HEAP_IOVMM (1ul << 30) /* common carveout heaps */ -#define NVMAP_HEAP_CARVEOUT_VPR (1ul<<28) -#define NVMAP_HEAP_CARVEOUT_TSEC (1ul<<27) -#define NVMAP_HEAP_CARVEOUT_VIDMEM (1ul<<26) -#define NVMAP_HEAP_CARVEOUT_GPU (1ul << 3) -#define NVMAP_HEAP_CARVEOUT_FSI (1ul<<2) -#define NVMAP_HEAP_CARVEOUT_IVM (1ul<<1) -#define NVMAP_HEAP_CARVEOUT_GENERIC (1ul<<0) +#define NVMAP_HEAP_CARVEOUT_VPR (1ul << 28) +#define NVMAP_HEAP_CARVEOUT_TSEC (1ul << 27) +#define NVMAP_HEAP_CARVEOUT_VIDMEM (1ul << 26) +#define NVMAP_HEAP_CARVEOUT_VI (1ul << 4) +#define NVMAP_HEAP_CARVEOUT_GPU (1ul << 3) +#define NVMAP_HEAP_CARVEOUT_FSI (1ul << 2) +#define NVMAP_HEAP_CARVEOUT_IVM (1ul << 1) +#define NVMAP_HEAP_CARVEOUT_GENERIC (1ul << 0) #define NVMAP_HEAP_CARVEOUT_MASK (NVMAP_HEAP_IOVMM - 1) diff --git a/drivers/video/tegra/nvmap/nvmap_init.c b/drivers/video/tegra/nvmap/nvmap_init.c index 64c40c1e..baab97c2 100644 --- a/drivers/video/tegra/nvmap/nvmap_init.c +++ b/drivers/video/tegra/nvmap/nvmap_init.c @@ -91,12 +91,14 @@ static struct nvmap_platform_carveout nvmap_carveouts[] = { .size = 0, .numa_node_id = 0, }, - /* Need uninitialized entries for IVM carveouts */ [5] = { - .name = NULL, - .usage_mask = NVMAP_HEAP_CARVEOUT_IVM, + .name = "vimem", + .usage_mask = NVMAP_HEAP_CARVEOUT_VI, + .base = 0, + .size = 0, .numa_node_id = 0, }, + /* Need uninitialized entries for IVM carveouts */ [6] = { .name = NULL, .usage_mask = NVMAP_HEAP_CARVEOUT_IVM, @@ -112,11 +114,16 @@ static struct nvmap_platform_carveout nvmap_carveouts[] = { .usage_mask = NVMAP_HEAP_CARVEOUT_IVM, .numa_node_id = 0, }, + [9] = { + .name = NULL, + .usage_mask = NVMAP_HEAP_CARVEOUT_IVM, + .numa_node_id = 0, + }, }; static struct nvmap_platform_data nvmap_data = { .carveouts = nvmap_carveouts, - .nr_carveouts = 5, + .nr_carveouts = 6, }; static struct nvmap_platform_carveout *nvmap_get_carveout_pdata(const char *name) @@ -149,12 +156,21 @@ static int __init nvmap_populate_ivm_carveout(struct device *dev) struct tegra_hv_ivm_cookie *ivm; unsigned long long id; unsigned int guestid, result; + bool is_vi_heap; if (!of_phandle_iterator_init(&it, dev->of_node, "memory-region", NULL, 0)) { while (!of_phandle_iterator_next(&it) && it.node) { - if (of_device_is_available(it.node) && - of_device_is_compatible(it.node, "nvidia,ivm_carveout") > 0) { - co = nvmap_get_carveout_pdata("nvidia,ivm_carveout"); + is_vi_heap = false; + if (of_device_is_available(it.node)) { + if (of_device_is_compatible(it.node, "nvidia,ivm_carveout") > 0) { + co = nvmap_get_carveout_pdata("nvidia,ivm_carveout"); + } else if (of_device_is_compatible(it.node, + "nvidia,vi_carveout") > 0) { + co = nvmap_get_carveout_pdata("vimem"); + is_vi_heap = true; + } else + continue; + if (!co) { ret = -ENOMEM; goto err; @@ -198,25 +214,29 @@ static int __init nvmap_populate_ivm_carveout(struct device *dev) /* See if this VM can allocate (or just create handle from ID) * generated by peer partition */ - prop = of_get_property(it.node, "alloc", NULL); - if (!prop) { - pr_err("failed to read alloc property\n"); - ret = -EINVAL; - goto fail; - } + if (!is_vi_heap) { + prop = of_get_property(it.node, "alloc", NULL); + if (!prop) { + pr_err("failed to read alloc property\n"); + ret = -EINVAL; + goto fail; + } - name = kzalloc(32, GFP_KERNEL); - if (!name) { - ret = -ENOMEM; - goto fail; - } + name = kzalloc(32, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto fail; + } - co->can_alloc = of_read_number(prop, 1); - co->is_ivm = true; - sprintf(name, "ivm%02u%02u%02d", co->vmid, co->peer, co->can_alloc); - pr_info("IVM carveout IPA:%p, size=%zu, peer vmid=%u, name=%s\n", - (void *)(uintptr_t)co->base, co->size, co->peer, name); - co->name = name; + co->can_alloc = of_read_number(prop, 1); + co->is_ivm = true; + sprintf(name, "ivm%02u%02u%02d", co->vmid, co->peer, + co->can_alloc); + pr_info("IVM carveout IPA:%p, size=%zu, peer vmid=%u," + "name=%s\n", (void *)(uintptr_t)co->base, co->size, + co->peer, name); + co->name = name; + } if (check_add_overflow(nvmap_data.nr_carveouts, 1U, &result)) { co->name = NULL; @@ -226,12 +246,12 @@ static int __init nvmap_populate_ivm_carveout(struct device *dev) } nvmap_data.nr_carveouts = result; - } } } return 0; fail: + (void)tegra_hv_mempool_unreserve(ivm); co->base = 0; co->peer = 0; co->size = 0; @@ -381,7 +401,8 @@ int __init nvmap_init(struct platform_device *pdev) if (!of_phandle_iterator_init(&it, np, "memory-region", NULL, 0)) { while (!of_phandle_iterator_next(&it) && it.node) { if (of_device_is_available(it.node) && - !of_device_is_compatible(it.node, "nvidia,ivm_carveout")) { + !of_device_is_compatible(it.node, "nvidia,ivm_carveout") && + !of_device_is_compatible(it.node, "nvidia,vi_carveout")) { rmem2 = of_reserved_mem_lookup(it.node); if (!rmem2) { if (!of_property_read_string(it.node, "compatible", &compp))