mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-23 01:31:30 +03:00
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:
committed by
mobile promotions
parent
294fdd64e5
commit
a010f20be9
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user