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 <ajithk@nvidia.com>
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 <vincentc@nvidia.com>
Reviewed-by: Bhushan Rayrikar <brayrikar@nvidia.com>
Reviewed-by: Igor Mitsyanko <imitsyanko@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: Frank Chen <frankc@nvidia.com>
Reviewed-by: Shiva Dubey <sdubey@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
Tested-by: Frank Chen <frankc@nvidia.com>
This commit is contained in:
Ajith Kumar
2022-10-30 04:51:36 +00:00
committed by mobile promotions
parent 294fdd64e5
commit a010f20be9

View File

@@ -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;