Files
android_kernel_samsung_sm86…/drivers/cam_isp/cam_isp_dev.c
Sokchetra Eung c87d8891b9 msm: camera: common: Enhance error injection framework
Update from error injection framework to event injection framework to
support PF event inducement and node event. Different set of user
input parameters are required dependent on which event to injection.

ICP and ISP support error event and page fault event injection. JPEG
supports node event and page fault event injection. However, buf done
error injection is only supported for JPEG and ICP.

Create a query API to check whether PF is fatal for a context bank.
Using the API, if PF is fatal, page fault event injection is not
supported for the device that owns the context bank.

Make change to JPEG context event callback handling to account for
various events including Event Injection event.

CRs-Fixed: 3210139
Change-Id: I582ee0bda8dbf631ece2522a5a8145f38ec71928
Signed-off-by: Sokchetra Eung <quic_eung@quicinc.com>
2022-09-29 15:06:49 -07:00

333 خطوط
7.9 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/iommu.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <media/cam_req_mgr.h>
#include "cam_isp_dev.h"
#include "cam_hw_mgr_intf.h"
#include "cam_isp_hw_mgr_intf.h"
#include "cam_node.h"
#include "cam_debug_util.h"
#include "cam_smmu_api.h"
#include "camera_main.h"
#include "cam_common_util.h"
#include "cam_context_utils.h"
static struct cam_isp_dev g_isp_dev;
static int cam_isp_dev_evt_inject_cb(void *inject_args)
{
struct cam_common_inject_evt_param *inject_params = inject_args;
int i;
for (i = 0; i < g_isp_dev.max_context; i++) {
if (g_isp_dev.ctx[i].dev_hdl == inject_params->dev_hdl) {
cam_context_add_evt_inject(&g_isp_dev.ctx[i],
&inject_params->evt_params);
return 0;
}
}
CAM_ERR(CAM_ISP, "No dev hdl found %d", inject_params->dev_hdl);
return -ENODEV;
}
static void cam_isp_dev_iommu_fault_handler(struct cam_smmu_pf_info *pf_smmu_info)
{
int i, rc;
struct cam_node *node = NULL;
struct cam_hw_dump_pf_args pf_args = {0};
if (!pf_smmu_info || !pf_smmu_info->token) {
CAM_ERR(CAM_ISP, "invalid token in page handler cb");
return;
}
node = (struct cam_node *)pf_smmu_info->token;
pf_args.pf_smmu_info = pf_smmu_info;
for (i = 0; i < node->ctx_size; i++) {
cam_context_dump_pf_info(&(node->ctx_list[i]), &pf_args);
if (pf_args.pf_context_info.ctx_found)
/* Faulted ctx found */
break;
}
if (i == node->ctx_size) {
/* Faulted ctx not found. Report PF to userspace */
rc = cam_context_send_pf_evt(NULL, &pf_args);
if (rc)
CAM_ERR(CAM_ISP,
"Failed to notify PF event to userspace rc: %d", rc);
}
}
static const struct of_device_id cam_isp_dt_match[] = {
{
.compatible = "qcom,cam-isp"
},
{}
};
static int cam_isp_subdev_open(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK);
mutex_lock(&g_isp_dev.isp_mutex);
g_isp_dev.open_cnt++;
mutex_unlock(&g_isp_dev.isp_mutex);
cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK);
return 0;
}
static int cam_isp_subdev_close_internal(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
int rc = 0;
struct cam_node *node = v4l2_get_subdevdata(sd);
mutex_lock(&g_isp_dev.isp_mutex);
if (g_isp_dev.open_cnt <= 0) {
CAM_DBG(CAM_ISP, "ISP subdev is already closed");
rc = -EINVAL;
goto end;
}
g_isp_dev.open_cnt--;
if (!node) {
CAM_ERR(CAM_ISP, "Node ptr is NULL");
rc = -EINVAL;
goto end;
}
if (g_isp_dev.open_cnt == 0)
cam_node_shutdown(node);
end:
mutex_unlock(&g_isp_dev.isp_mutex);
return rc;
}
static int cam_isp_subdev_close(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
bool crm_active = cam_req_mgr_is_open();
if (crm_active) {
CAM_DBG(CAM_ISP, "CRM is ACTIVE, close should be from CRM");
return 0;
}
return cam_isp_subdev_close_internal(sd, fh);
}
static const struct v4l2_subdev_internal_ops cam_isp_subdev_internal_ops = {
.close = cam_isp_subdev_close,
.open = cam_isp_subdev_open,
};
static int cam_isp_dev_component_bind(struct device *dev,
struct device *master_dev, void *data)
{
int rc = -1;
int i;
struct cam_hw_mgr_intf hw_mgr_intf;
struct cam_node *node;
const char *compat_str = NULL;
struct platform_device *pdev = to_platform_device(dev);
int iommu_hdl = -1;
rc = of_property_read_string_index(pdev->dev.of_node, "arch-compat", 0,
(const char **)&compat_str);
g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops;
g_isp_dev.sd.close_seq_prior = CAM_SD_CLOSE_HIGH_PRIORITY;
/* Initialize the v4l2 subdevice first. (create cam_node) */
if (strnstr(compat_str, "ife", strlen(compat_str))) {
rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME,
CAM_IFE_DEVICE_TYPE);
g_isp_dev.isp_device_type = CAM_IFE_DEVICE_TYPE;
g_isp_dev.max_context = CAM_IFE_CTX_MAX;
} else if (strnstr(compat_str, "tfe", strlen(compat_str))) {
rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME,
CAM_TFE_DEVICE_TYPE);
g_isp_dev.isp_device_type = CAM_TFE_DEVICE_TYPE;
g_isp_dev.max_context = CAM_TFE_CTX_MAX;
} else {
CAM_ERR(CAM_ISP, "Invalid ISP hw type %s", compat_str);
rc = -EINVAL;
goto err;
}
if (rc) {
CAM_ERR(CAM_ISP, "ISP cam_subdev_probe failed!");
goto err;
}
node = (struct cam_node *) g_isp_dev.sd.token;
memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf));
g_isp_dev.ctx = kcalloc(g_isp_dev.max_context,
sizeof(struct cam_context),
GFP_KERNEL);
if (!g_isp_dev.ctx) {
CAM_ERR(CAM_ISP,
"Mem Allocation failed for ISP base context");
goto unregister;
}
g_isp_dev.ctx_isp = kcalloc(g_isp_dev.max_context,
sizeof(struct cam_isp_context),
GFP_KERNEL);
if (!g_isp_dev.ctx_isp) {
CAM_ERR(CAM_ISP,
"Mem Allocation failed for Isp private context");
kfree(g_isp_dev.ctx);
g_isp_dev.ctx = NULL;
goto unregister;
}
rc = cam_isp_hw_mgr_init(compat_str, &hw_mgr_intf, &iommu_hdl);
if (rc != 0) {
CAM_ERR(CAM_ISP, "Can not initialized ISP HW manager!");
goto kfree;
}
for (i = 0; i < g_isp_dev.max_context; i++) {
rc = cam_isp_context_init(&g_isp_dev.ctx_isp[i],
&g_isp_dev.ctx[i],
&node->crm_node_intf,
&node->hw_mgr_intf,
i,
g_isp_dev.isp_device_type, iommu_hdl);
if (rc) {
CAM_ERR(CAM_ISP, "ISP context init failed!");
goto kfree;
}
}
cam_common_register_evt_inject_cb(cam_isp_dev_evt_inject_cb,
CAM_COMMON_EVT_INJECT_HW_ISP);
rc = cam_node_init(node, &hw_mgr_intf, g_isp_dev.ctx,
g_isp_dev.max_context, CAM_ISP_DEV_NAME);
if (rc) {
CAM_ERR(CAM_ISP, "ISP node init failed!");
goto kfree;
}
node->sd_handler = cam_isp_subdev_close_internal;
cam_smmu_set_client_page_fault_handler(iommu_hdl,
cam_isp_dev_iommu_fault_handler, node);
mutex_init(&g_isp_dev.isp_mutex);
CAM_DBG(CAM_ISP, "Component bound successfully");
return 0;
kfree:
kfree(g_isp_dev.ctx);
g_isp_dev.ctx = NULL;
kfree(g_isp_dev.ctx_isp);
g_isp_dev.ctx_isp = NULL;
unregister:
rc = cam_subdev_remove(&g_isp_dev.sd);
err:
return rc;
}
static void cam_isp_dev_component_unbind(struct device *dev,
struct device *master_dev, void *data)
{
int rc = 0;
int i;
const char *compat_str = NULL;
struct platform_device *pdev = to_platform_device(dev);
rc = of_property_read_string_index(pdev->dev.of_node, "arch-compat", 0,
(const char **)&compat_str);
cam_isp_hw_mgr_deinit(compat_str);
/* clean up resources */
for (i = 0; i < g_isp_dev.max_context; i++) {
rc = cam_isp_context_deinit(&g_isp_dev.ctx_isp[i]);
if (rc)
CAM_ERR(CAM_ISP, "ISP context %d deinit failed",
i);
}
kfree(g_isp_dev.ctx);
g_isp_dev.ctx = NULL;
kfree(g_isp_dev.ctx_isp);
g_isp_dev.ctx_isp = NULL;
rc = cam_subdev_remove(&g_isp_dev.sd);
if (rc)
CAM_ERR(CAM_ISP, "Unregister failed rc: %d", rc);
memset(&g_isp_dev, 0, sizeof(g_isp_dev));
}
const static struct component_ops cam_isp_dev_component_ops = {
.bind = cam_isp_dev_component_bind,
.unbind = cam_isp_dev_component_unbind,
};
static int cam_isp_dev_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &cam_isp_dev_component_ops);
return 0;
}
static int cam_isp_dev_probe(struct platform_device *pdev)
{
int rc = 0;
CAM_DBG(CAM_ISP, "Adding ISP dev component");
rc = component_add(&pdev->dev, &cam_isp_dev_component_ops);
if (rc)
CAM_ERR(CAM_ISP, "failed to add component rc: %d", rc);
return rc;
}
struct platform_driver isp_driver = {
.probe = cam_isp_dev_probe,
.remove = cam_isp_dev_remove,
.driver = {
.name = "cam_isp",
.owner = THIS_MODULE,
.of_match_table = cam_isp_dt_match,
.suppress_bind_attrs = true,
},
};
int cam_isp_dev_init_module(void)
{
return platform_driver_register(&isp_driver);
}
void cam_isp_dev_exit_module(void)
{
platform_driver_unregister(&isp_driver);
}
MODULE_DESCRIPTION("MSM ISP driver");
MODULE_LICENSE("GPL v2");