From a010f20be9ac8cd1fcbb4a2259f9b5dd1dbb4dcc Mon Sep 17 00:00:00 2001 From: Ajith Kumar Date: Sun, 30 Oct 2022 04:51:36 +0000 Subject: [PATCH] tegra: camera: fix iova address calculation On SIPL stack, VI engine status memory which is allocated by SIPL span across multiple memory pages. IOVA calculations in KMD as per pinned pages did not taken to account the multiple pages and calculated IOVA based on first page base address. This lead to VI falcon access the passed incorrect iova address which caused Kernel OOPS at random places. To fix this, calculate the IOVA based on adjusting offset with respect to right page by traversing the scatterlist. For older kernel versions(4.9) being used in some android packages, the existing IOVA mappping is kept as it is, as it doesn't support scatterlist. Bug 3770879 Change-Id: I27d6850aaecbb1e095e836adee041f3f4747e2b7 Signed-off-by: Ajith Kumar Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2800018 (cherry picked from commit d27f901f5e21380441f3d1afd19f1fdbd160b06f) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2799843 (cherry picked from commit 2856d6a5aa5a56f0a1c543ad6c2ba8373282c2c5) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2864345 Reviewed-by: Vincent Chung Reviewed-by: Bhushan Rayrikar Reviewed-by: Igor Mitsyanko Reviewed-by: svc-mobile-coverity Reviewed-by: svc-mobile-cert Reviewed-by: Frank Chen Reviewed-by: Shiva Dubey GVS: Gerrit_Virtual_Submit Tested-by: Frank Chen --- .../camera/fusa-capture/capture-common.c | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c index 93079ba4..40a584f9 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-common.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2017-2022 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved. /** * @file drivers/media/platform/tegra/camera/fusa-capture/capture-common.c @@ -116,11 +116,39 @@ static inline enum dma_data_direction flag_dma_direction( * @returns Physical address of scatterlist mapping */ static inline dma_addr_t mapping_iova( - const struct capture_mapping *pin) + const struct capture_mapping *pin, + uint64_t mem_offset) { - dma_addr_t addr = sg_dma_address(pin->sgt->sgl); + dma_addr_t iova = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) + iova = (sg_dma_address(pin->sgt->sgl) != 0) ? sg_dma_address(pin->sgt->sgl) : + sg_phys(pin->sgt->sgl); + iova += mem_offset; +#else + struct scatterlist *sg; + uint64_t mem_offset_adjusted = mem_offset; + int i; - return (addr != 0) ? addr : sg_phys(pin->sgt->sgl); + /* Traverse the scatterlist and adjust the offset + * as per the page block. This is needed in case + * where memory spans across multiple pages and + * is non-contiguous + */ + for_each_sgtable_dma_sg(pin->sgt, sg, i) { + if (mem_offset_adjusted < sg_dma_len(sg)) { + iova = (sg_dma_address(sg) == 0) ? sg_phys(sg) : sg_dma_address(sg); + iova += mem_offset_adjusted; + if (iova < mem_offset_adjusted) { + /** It means iova has wrapped */ + return 0; + } + break; + } + mem_offset_adjusted -= sg_dma_len(sg); + } +#endif + + return iova; } /** @@ -471,14 +499,18 @@ int capture_common_pin_and_get_iova(struct capture_buffer_table *buf_ctx, buf = mapping_buf(map); size = buf->size; - iova = mapping_iova(map); - if (mem_offset >= size) { pr_err("%s: offset is out of bounds\n", __func__); return -EINVAL; } - *meminfo_base_address = iova + mem_offset; + iova = mapping_iova(map, mem_offset); + if (iova == 0) { + pr_err("%s: Invalid iova\n", __func__); + return -EINVAL; + } + + *meminfo_base_address = iova; *meminfo_size = size - mem_offset; unpins->data[unpins->num_unpins] = map;