nvidia-oot: cameraSW: add data validation to dt reads

+ Add the following data validation checks based on
  gaps identified when inspecting code for
  SHR-9320:
  + FSYNC: Add check to ensure existence of generators
    property before parse
  + FSYNC: Add check to ensure generators in default
    group adhere to LCM rule
  + CDI: Add check to ensure reg_len / dat_len do
    not exceed 2 bytes
  + CDI: Ensure err is set before jumping to err_probe
  + CDI: Jump to err_probe if IOExpander i2c-bus read
    fails
  + CDI-TCA: Return error if reg_len or dat_len
    out of expected range
  + FuSaCap: Ensure isp/vi-max-channels validated
  + VI: Add check for vi-mapping index found (this was
    already caught in existing code, but error message
    was non-specific)
  + camera_common: Add check for err that was set but
    never read
  + RTCPU: Add debug prints for properties not found

Jira CAMERASW-30537
Change-Id: I9953029f594c0153d6c335913944fb8906adedd9
Signed-off-by: kevixie <kevixie@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3280557
Reviewed-by: Vincent Chung <vincentc@nvidia.com>
Reviewed-by: Frank Chen <frankc@nvidia.com>
Reviewed-by: Mohit Ingale <mohiti@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
kevixie
2025-01-03 16:23:18 -08:00
committed by Jon Hunter
parent 0b94a70702
commit 5ce08ee3ce
7 changed files with 208 additions and 49 deletions

View File

@@ -1,5 +1,7 @@
/* Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: GPL-2.0-only
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-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,
@@ -1174,6 +1176,11 @@ static int cam_fsync_create_default_group(struct cam_fsync_controller *controlle
return err;
}
}
err = cam_fsync_group_verify_generators_lcm(group);
if (err != 0) {
dev_err(controller->dev, "Generator LCM check failed");
return err;
}
list_add_tail(&group->list, &controller->groups);
return err;
@@ -1238,6 +1245,10 @@ static int cam_fsync_find_and_add_groups(struct cam_fsync_controller *controller
num_generators = of_property_count_elems_of_size(np, "generators",
sizeof(u32));
if (num_generators < 0) {
dev_err(controller->dev, "Unable to parse generators: %d\n", num_generators);
return num_generators;
}
for (i = 0; i < num_generators; i++) {
gen = of_parse_phandle(np, "generators", i);
err = cam_fsync_add_generator(group, gen);

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES.
* SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -271,6 +271,10 @@ int camera_common_parse_clocks(struct device *dev,
}
err = of_property_read_u32(np, "parent-clk-index",
&parentclk_index);
if (err) {
dev_err(dev, "Failed to find parent clk index\n");
return err;
}
}
for (i = 0; i < numclocks; i++) {

View File

@@ -1,5 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-FileCopyrightText: Copyright (c) 2017-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.
*/
/**
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c
@@ -36,15 +48,18 @@
#define CAPTURE_CHANNEL_ISP_INVALID_ID U16_C(0xFFFF)
/**
* @brief The default number of ISP channels to be used if not specified in
* the device tree.
* @brief Maximum number of ISP channels supported by KMD
*/
#define DEFAULT_ISP_CHANNELS U32_C(16)
#define NUM_ISP_CHANNELS U32_C(16)
/**
* @brief Maximum number of ISP channels supported by KMD for T26x
*/
#define NUM_ISP_CHANNELS_T26x U32_C(32)
/**
* @brief Maximum number of ISP devices supported.
*/
#define MAX_ISP_UNITS U32_C(0x2)
#define MAX_ISP_UNITS U32_C(0x2)
/**
* @brief The Capture-ISP standalone driver context.
@@ -2330,6 +2345,36 @@ int isp_capture_buffer_request(
return err;
}
/**
* @brief Helper to parse isp-devices Chip ID
*
* @param[in] of_node Pointer to @ref device_node
* containing isp-devices phandle
* @returns true If isp-devices is configured for T26X.
* @returns false If T26X not mentioned.
*/
static inline bool isp_capture_is_t26x(struct device_node *of_node)
{
struct device_node *node;
const char *compatible;
int ret = 0;
bool is_t26x = false;
node = of_parse_phandle(of_node, "nvidia,isp-devices", 0);
if (node == NULL)
return false;
ret = of_property_read_string(node, "compatible", &compatible);
if (ret != 0) {
of_node_put(node);
return false;
}
is_t26x = (strstr(compatible, "tegra26") != NULL);
of_node_put(node);
return is_t26x;
}
static int capture_isp_probe(struct platform_device *pdev)
{
uint32_t i;
@@ -2345,10 +2390,23 @@ static int capture_isp_probe(struct platform_device *pdev)
info->num_isp_devices = 0;
(void)of_property_read_u32(dev->of_node, "nvidia,isp-max-channels",
err = of_property_read_u32(dev->of_node, "nvidia,isp-max-channels",
&info->max_isp_channels);
if (info->max_isp_channels == 0)
info->max_isp_channels = DEFAULT_ISP_CHANNELS;
if (err < 0) {
err = -EINVAL;
goto cleanup;
}
if (isp_capture_is_t26x(dev->of_node)) {
if (info->max_isp_channels > NUM_ISP_CHANNELS_T26x) {
err = -EINVAL;
goto cleanup;
}
} else {
if ((info->max_isp_channels == 0) || (info->max_isp_channels > NUM_ISP_CHANNELS)) {
err = -EINVAL;
goto cleanup;
}
}
for (i = 0; ; i++) {
struct device_node *node;

View File

@@ -70,6 +70,11 @@
*/
#define DEFAULT_VI_CHANNELS U32_C(64)
/**
* @brief Maximum number of VI channels supported by KMD in total
*/
#define NUM_VI_CHANNELS U32_C(72)
/**
* @brief Maximum number of VI devices supported.
*/
@@ -1621,6 +1626,7 @@ EXPORT_SYMBOL_GPL(vi_capture_set_progress_status_notifier);
static int csi_vi_get_mapping_table(struct platform_device *pdev)
{
uint32_t index = 0;
int err = 0;
struct device *dev = &pdev->dev;
struct tegra_capture_vi_data *info = platform_get_drvdata(pdev);
@@ -1659,10 +1665,16 @@ static int csi_vi_get_mapping_table(struct platform_device *pdev)
uint32_t stream_index = NVCSI_STREAM_INVALID_ID;
uint32_t vi_unit_id = INVALID_VI_UNIT_ID;
(void)of_property_read_u32_index(np,
err = of_property_read_u32_index(np,
"nvidia,vi-mapping",
2 * index,
&stream_index);
if (err) {
dev_err(dev,
"%s: ERR %d: missing property nvidia,vi-mapping or csi_stream_id at index %d",
__func__, err, index);
return err;
}
/* Check for valid/duplicate csi-stream-id */
if (stream_index >= MAX_NVCSI_STREAM_IDS ||
@@ -1672,10 +1684,16 @@ static int csi_vi_get_mapping_table(struct platform_device *pdev)
return -EINVAL;
}
(void)of_property_read_u32_index(np,
err = of_property_read_u32_index(np,
"nvidia,vi-mapping",
2 * index + 1,
&vi_unit_id);
if (err) {
dev_err(dev,
"%s: ERR %d: missing property nvidia,vi-mapping or vi_unit_id at index %d",
__func__, err, index);
return err;
}
/* check for valid vi-unit-id */
if (vi_unit_id >= MAX_VI_UNITS) {
@@ -1713,8 +1731,13 @@ static int capture_vi_probe(struct platform_device *pdev)
info->num_vi_devices = 0;
(void)of_property_read_u32(dev->of_node, "nvidia,vi-max-channels",
err = of_property_read_u32(dev->of_node, "nvidia,vi-max-channels",
&info->max_vi_channels);
if (err || info->max_vi_channels > NUM_VI_CHANNELS) {
err = -EINVAL;
goto cleanup;
}
if (info->max_vi_channels == 0)
info->max_vi_channels = DEFAULT_VI_CHANNELS;

View File

@@ -1,5 +1,17 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-FileCopyrightText: Copyright (c) 2022-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.
*/
#ifndef __CDI_TCA9539_PRIV_H__
#define __CDI_TCA9539_PRIV_H__
@@ -31,19 +43,15 @@ static int tca9539_raw_wr(
dev_dbg(dev, "%s\n", __func__);
if (tca9539->reg_len == 2) {
data[0] = (u8)((offset >> 8) & 0xff);
data[1] = (u8)(offset & 0xff);
data[2] = val;
size += 2;
} else if (tca9539->reg_len == 1) {
data[0] = (u8)(offset & 0xff);
data[1] = val;
size += 1;
} else if ((tca9539->reg_len == 0) ||
(tca9539->reg_len > 3)) {
return 0;
}
if (tca9539->dat_len != 1)
return -EINVAL;
if (tca9539->reg_len != 1)
return -EINVAL;
data[0] = (u8)(offset & 0xff);
data[1] = val;
size += 1;
num_msgs = size / MAX_MSG_SIZE;
num_msgs += (size % MAX_MSG_SIZE) ? 1 : 0;
@@ -96,11 +104,13 @@ static int tca9539_raw_rd(
dev_dbg(dev, "%s\n", __func__);
if (tca9539->reg_len == 2) {
data[0] = (u8)((offset >> 8) & 0xff);
data[1] = (u8)(offset & 0xff);
} else if (tca9539->reg_len == 1)
data[0] = (u8)(offset & 0xff);
if (tca9539->dat_len != 1)
return -EINVAL;
if (tca9539->reg_len != 1)
return -EINVAL;
data[0] = (u8)(offset & 0xff);
i2cmsg[0].addr = tca9539->addr;
i2cmsg[0].len = tca9539->reg_len;

View File

@@ -1,5 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (C) 2015-2024 NVIDIA CORPORATION. All rights reserved.
/* SPDX-FileCopyrightText: Copyright (c) 2015-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.
*/
#include <nvidia/conftest.h>
@@ -1794,10 +1806,13 @@ static int cdi_mgr_probe(struct platform_device *pdev)
if (pd->num_pwr_gpios > 0) {
for (i = 0; i < pd->num_pwr_gpios; i++) {
if (!gpio_is_valid(pd->pwr_gpios[i]))
if (!gpio_is_valid(pd->pwr_gpios[i])) {
err = -EINVAL;
goto err_probe;
}
if (gpio_request(pd->pwr_gpios[i], "pwdn-gpios")) {
err = gpio_request(pd->pwr_gpios[i], "pwdn-gpios");
if (err) {
dev_err(&pdev->dev, "failed to req GPIO: %d\n",
pd->pwr_gpios[i]);
goto err_probe;
@@ -1905,14 +1920,18 @@ static int cdi_mgr_probe(struct platform_device *pdev)
if (child_tca9539 != NULL) {
err = of_property_read_u32(child_tca9539, "i2c-bus",
&cdi_mgr->tca9539.bus);
if (err)
cdi_mgr->tca9539.bus = pd->bus;
if (err) {
dev_err(&pdev->dev, "%s: ERROR %d failed to find IOExpander i2c-bus property\n",
__func__, err);
goto err_probe;
}
err = of_property_read_u32(child_tca9539, "addr",
&cdi_mgr->tca9539.addr);
if (err || !cdi_mgr->tca9539.addr) {
dev_err(&pdev->dev, "%s: ERROR %d addr = %d\n",
__func__, err,
cdi_mgr->tca9539.addr);
err = -EINVAL;
goto err_probe;
}
err = of_property_read_u32(child_tca9539, "reg_len",
@@ -1921,6 +1940,7 @@ static int cdi_mgr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s: ERROR %d reg_len = %d\n",
__func__, err,
cdi_mgr->tca9539.reg_len);
err = -EINVAL;
goto err_probe;
}
err = of_property_read_u32(child_tca9539, "dat_len",
@@ -1929,6 +1949,7 @@ static int cdi_mgr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s: ERROR %d dat_len = %d\n",
__func__, err,
cdi_mgr->tca9539.dat_len);
err = -EINVAL;
goto err_probe;
}
err = of_property_read_u32(child_tca9539->parent,
@@ -1954,11 +1975,19 @@ static int cdi_mgr_probe(struct platform_device *pdev)
cdi_mgr->tca9539.reg_len /= 8;
cdi_mgr->tca9539.dat_len /= 8;
if (cdi_mgr->tca9539.reg_len != 1 || cdi_mgr->tca9539.dat_len != 1) {
dev_err(&pdev->dev, "%s invalid reg_len = %d or dat_len = %d\n",
__func__, cdi_mgr->tca9539.reg_len,
cdi_mgr->tca9539.dat_len);
err = -EINVAL;
goto err_probe;
}
cdi_mgr->tca9539.enable = 1;
cdi_mgr->tca9539.adap = i2c_get_adapter(cdi_mgr->tca9539.bus);
if (!cdi_mgr->tca9539.adap) {
dev_err(&pdev->dev, "%s no such i2c bus %d\n",
__func__, cdi_mgr->tca9539.bus);
err = -EINVAL;
goto err_probe;
}
@@ -1969,27 +1998,31 @@ static int cdi_mgr_probe(struct platform_device *pdev)
/* the registers in TCA9539 */
/* Use the IO expander to control PWDN signals */
if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */
if (tca9539_wr(cdi_mgr, 0x6, 0x0E) != 0) {
err = tca9539_wr(cdi_mgr, 0x6, 0x0E);
if (err != 0) {
dev_err(&pdev->dev,
"%s: ERR %d: TCA9539: Failed to select PWDN signal source\n",
__func__, err);
goto err_probe;
}
/* Output low for AGGA/B/C/D_PWRDN */
if (tca9539_wr(cdi_mgr, 0x2, 0x0E) != 0) {
err = tca9539_wr(cdi_mgr, 0x2, 0x0E);
if (err != 0) {
dev_err(&pdev->dev,
"%s: ERR %d: TCA9539: Failed to set the output level\n",
__func__, err);
goto err_probe;
}
} else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */
if (tca9539_wr(cdi_mgr, 0x6, 0xC0) != 0) {
err = tca9539_wr(cdi_mgr, 0x6, 0xC0);
if (err != 0) {
dev_err(&pdev->dev,
"%s: ERR %d: TCA9539: Failed to select FS selection signal source\n",
__func__, err);
goto err_probe;
}
if (tca9539_wr(cdi_mgr, 0x7, 0x70) != 0) {
err = tca9539_wr(cdi_mgr, 0x7, 0x70);
if (err != 0) {
dev_err(&pdev->dev,
"%s: ERR %d: TCA9539: Failed to select PWDN signal source\n",
__func__, err);
@@ -2002,17 +2035,19 @@ static int cdi_mgr_probe(struct platform_device *pdev)
cdi_mgr->cim_frsync[0],
cdi_mgr->cim_frsync[1],
cdi_mgr->cim_frsync[2]);
if (tca9539_wr(cdi_mgr, 0x2,
err = tca9539_wr(cdi_mgr, 0x2,
(cdi_mgr->cim_frsync[2] << 4) |
(cdi_mgr->cim_frsync[1] << 2) |
(cdi_mgr->cim_frsync[0])) < 0) {
(cdi_mgr->cim_frsync[0]));
if (err < 0) {
dev_err(&pdev->dev,
"%s: ERR %d: TCA9539: Failed to set FRSYNC control logic\n",
__func__, err);
goto err_probe;
}
/* Output low for AGGA/B/C/D_PWRDN */
if (tca9539_wr(cdi_mgr, 0x3, 0x00) != 0) {
err = tca9539_wr(cdi_mgr, 0x3, 0x00);
if (err != 0) {
dev_err(&pdev->dev,
"%s: ERR %d: TCA9539: Failed to set the output level\n",
__func__, err);

View File

@@ -1,5 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-FileCopyrightText: Copyright (c) 2022-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.
*/
#include <nvidia/conftest.h>
#include <linux/tegra-camera-rtcpu.h>
@@ -832,7 +844,9 @@ static int tegra_cam_rtcpu_probe(struct platform_device *pdev)
}
name = pdata->name;
of_property_read_string(dev->of_node, "nvidia,cpu-name", &name);
ret = of_property_read_string(dev->of_node, "nvidia,cpu-name", &name);
if (ret)
dev_dbg(dev, "no device property, cpu-name, setting to parent name\n");
dev_dbg(dev, "probing RTCPU on %s\n", name);
@@ -854,11 +868,15 @@ static int tegra_cam_rtcpu_probe(struct platform_device *pdev)
goto fail;
rtcpu->max_reboot_retry = 3;
(void)of_property_read_u32(dev->of_node, NV(max-reboot),
ret = of_property_read_u32(dev->of_node, NV(max-reboot),
&rtcpu->max_reboot_retry);
if (ret)
dev_dbg(dev, "no device property, max-reboot, setting to default (3)\n");
timeout = 2000;
(void)of_property_read_u32(dev->of_node, "nvidia,cmd-timeout", &timeout);
ret = of_property_read_u32(dev->of_node, "nvidia,cmd-timeout", &timeout);
if (ret)
dev_dbg(dev, "no device property, cmd-timeout, setting to default (2000)\n");
rtcpu->cmd_timeout = msecs_to_jiffies(timeout);