mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 04:42:04 -04:00
Merge "msm: camera: core: Add delay detection support" into camera-kernel.lnx.4.0
This commit is contained in:
commit
d0b010666c
10 changed files with 112 additions and 57 deletions
|
|
@ -26,6 +26,7 @@
|
|||
#include "camera_main.h"
|
||||
#include "cam_trace.h"
|
||||
#include "cam_req_mgr_workq.h"
|
||||
#include "cam_common_util.h"
|
||||
|
||||
#define CAM_CDM_BL_FIFO_WAIT_TIMEOUT 2000
|
||||
#define CAM_CDM_DBG_GEN_IRQ_USR_DATA 0xff
|
||||
|
|
@ -1215,8 +1216,10 @@ static void cam_hw_cdm_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
cam_req_mgr_thread_switch_delay_detect(
|
||||
payload->workq_scheduled_ts);
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"CDM workq schedule",
|
||||
payload->workq_scheduled_ts,
|
||||
CAM_WORKQ_SCHEDULE_TIME_THRESHOLD);
|
||||
|
||||
CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status);
|
||||
if (payload->irq_status &
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include "cam_cdm_soc.h"
|
||||
#include "cam_io_util.h"
|
||||
#include "cam_req_mgr_workq.h"
|
||||
#include "cam_common_util.h"
|
||||
|
||||
#define CAM_CDM_VIRTUAL_NAME "qcom,cam_virtual_cdm"
|
||||
|
||||
|
|
@ -34,8 +35,10 @@ static void cam_virtual_cdm_work(struct work_struct *work)
|
|||
cdm_hw = payload->hw;
|
||||
core = (struct cam_cdm *)cdm_hw->core_info;
|
||||
|
||||
cam_req_mgr_thread_switch_delay_detect(
|
||||
payload->workq_scheduled_ts);
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"Virtual CDM workq schedule",
|
||||
payload->workq_scheduled_ts,
|
||||
CAM_WORKQ_SCHEDULE_TIME_THRESHOLD);
|
||||
|
||||
if (payload->irq_status & 0x2) {
|
||||
struct cam_cdm_bl_cb_request_entry *node;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "cpastop_v680_100.h"
|
||||
#include "cpastop_v165_100.h"
|
||||
#include "cam_req_mgr_workq.h"
|
||||
#include "cam_common_util.h"
|
||||
|
||||
struct cam_camnoc_info *camnoc_info;
|
||||
struct cam_cpas_camnoc_qchannel *qchannel_info;
|
||||
|
|
@ -598,8 +599,10 @@ static void cam_cpastop_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
cam_req_mgr_thread_switch_delay_detect(
|
||||
payload->workq_scheduled_ts);
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"CPAS workq schedule",
|
||||
payload->workq_scheduled_ts,
|
||||
CAM_WORKQ_SCHEDULE_TIME_THRESHOLD);
|
||||
|
||||
cpas_hw = payload->hw;
|
||||
cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -11,8 +11,16 @@
|
|||
#include "cam_tasklet_util.h"
|
||||
#include "cam_irq_controller.h"
|
||||
#include "cam_debug_util.h"
|
||||
#include "cam_common_util.h"
|
||||
|
||||
#define CAM_TASKLETQ_SIZE 256
|
||||
|
||||
/* Threshold for scheduling delay in ms */
|
||||
#define CAM_TASKLET_SCHED_TIME_THRESHOLD 5
|
||||
|
||||
/* Threshold for execution delay in ms */
|
||||
#define CAM_TASKLET_EXE_TIME_THRESHOLD 10
|
||||
|
||||
#define CAM_TASKLETQ_SIZE 256
|
||||
|
||||
static void cam_tasklet_action(unsigned long data);
|
||||
|
||||
|
|
@ -27,6 +35,7 @@ static void cam_tasklet_action(unsigned long data);
|
|||
* @handler_priv: Private data passed at event subscribe
|
||||
* @bottom_half_handler: Function pointer for event handler in bottom
|
||||
* half context
|
||||
* @tasklet_enqueue_ts: enqueue time of tasklet
|
||||
*
|
||||
*/
|
||||
struct cam_tasklet_queue_cmd {
|
||||
|
|
@ -34,6 +43,7 @@ struct cam_tasklet_queue_cmd {
|
|||
void *payload;
|
||||
void *handler_priv;
|
||||
CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler;
|
||||
ktime_t tasklet_enqueue_ts;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -209,6 +219,7 @@ void cam_tasklet_enqueue_cmd(
|
|||
tasklet_cmd->bottom_half_handler = bottom_half_handler;
|
||||
tasklet_cmd->payload = evt_payload_priv;
|
||||
tasklet_cmd->handler_priv = handler_priv;
|
||||
tasklet_cmd->tasklet_enqueue_ts = ktime_get();
|
||||
spin_lock_irqsave(&tasklet->tasklet_lock, flags);
|
||||
list_add_tail(&tasklet_cmd->list,
|
||||
&tasklet->used_cmd_list);
|
||||
|
|
@ -322,12 +333,24 @@ static void cam_tasklet_action(unsigned long data)
|
|||
{
|
||||
struct cam_tasklet_info *tasklet_info = NULL;
|
||||
struct cam_tasklet_queue_cmd *tasklet_cmd = NULL;
|
||||
ktime_t curr_time;
|
||||
|
||||
tasklet_info = (struct cam_tasklet_info *)data;
|
||||
|
||||
while (!cam_tasklet_dequeue_cmd(tasklet_info, &tasklet_cmd)) {
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"Tasklet schedule",
|
||||
tasklet_cmd->tasklet_enqueue_ts,
|
||||
CAM_TASKLET_SCHED_TIME_THRESHOLD);
|
||||
curr_time = ktime_get();
|
||||
|
||||
tasklet_cmd->bottom_half_handler(tasklet_cmd->handler_priv,
|
||||
tasklet_cmd->payload);
|
||||
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"Tasklet execution",
|
||||
curr_time,
|
||||
CAM_TASKLET_EXE_TIME_THRESHOLD);
|
||||
cam_tasklet_put_cmd(tasklet_info, (void **)(&tasklet_cmd));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "cam_req_mgr_workq.h"
|
||||
#include "cam_debug_util.h"
|
||||
#include "cam_common_util.h"
|
||||
|
||||
#define WORKQ_ACQUIRE_LOCK(workq, flags) {\
|
||||
if ((workq)->in_irq) \
|
||||
|
|
@ -94,6 +95,7 @@ void cam_req_mgr_process_workq(struct work_struct *w)
|
|||
struct crm_workq_task *task;
|
||||
int32_t i = CRM_TASK_PRIORITY_0;
|
||||
unsigned long flags = 0;
|
||||
ktime_t curr_time;
|
||||
|
||||
if (!w) {
|
||||
CAM_ERR(CAM_CRM, "NULL task pointer can not schedule");
|
||||
|
|
@ -102,7 +104,11 @@ void cam_req_mgr_process_workq(struct work_struct *w)
|
|||
workq = (struct cam_req_mgr_core_workq *)
|
||||
container_of(w, struct cam_req_mgr_core_workq, work);
|
||||
|
||||
cam_req_mgr_thread_switch_delay_detect(workq->workq_scheduled_ts);
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"CRM workq schedule",
|
||||
workq->workq_scheduled_ts,
|
||||
CAM_WORKQ_SCHEDULE_TIME_THRESHOLD);
|
||||
curr_time = ktime_get();
|
||||
while (i < CRM_TASK_PRIORITY_MAX) {
|
||||
WORKQ_ACQUIRE_LOCK(workq, flags);
|
||||
while (!list_empty(&workq->task.process_head[i])) {
|
||||
|
|
@ -119,6 +125,10 @@ void cam_req_mgr_process_workq(struct work_struct *w)
|
|||
WORKQ_RELEASE_LOCK(workq, flags);
|
||||
i++;
|
||||
}
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"CRM workq execution",
|
||||
curr_time,
|
||||
CAM_WORKQ_EXE_TIME_THRESHOLD);
|
||||
}
|
||||
|
||||
int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
|
||||
|
|
@ -165,8 +175,8 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
|
|||
CAM_DBG(CAM_CRM, "enq task %pK pending_cnt %d",
|
||||
task, atomic_read(&workq->task.pending_cnt));
|
||||
|
||||
workq->workq_scheduled_ts = ktime_get();
|
||||
queue_work(workq->job, &workq->work);
|
||||
workq->workq_scheduled_ts = ktime_get();
|
||||
WORKQ_RELEASE_LOCK(workq, flags);
|
||||
end:
|
||||
return rc;
|
||||
|
|
@ -267,25 +277,3 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq)
|
|||
*crm_workq = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cam_req_mgr_thread_switch_delay_detect(ktime_t workq_scheduled)
|
||||
{
|
||||
uint64_t diff;
|
||||
ktime_t cur_time;
|
||||
struct timespec64 cur_ts;
|
||||
struct timespec64 workq_scheduled_ts;
|
||||
|
||||
cur_time = ktime_get();
|
||||
diff = ktime_ms_delta(cur_time, workq_scheduled);
|
||||
workq_scheduled_ts = ktime_to_timespec64(workq_scheduled);
|
||||
cur_ts = ktime_to_timespec64(cur_time);
|
||||
|
||||
if (diff > CAM_WORKQ_RESPONSE_TIME_THRESHOLD) {
|
||||
CAM_WARN_RATE_LIMIT(CAM_CRM,
|
||||
"Workq delay detected %ld:%06ld %ld:%06ld %ld:",
|
||||
workq_scheduled_ts.tv_sec,
|
||||
workq_scheduled_ts.tv_nsec/NSEC_PER_USEC,
|
||||
cur_ts.tv_sec, cur_ts.tv_nsec/NSEC_PER_USEC,
|
||||
diff);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CAM_REQ_MGR_WORKQ_H_
|
||||
|
|
@ -16,6 +16,12 @@
|
|||
|
||||
#include "cam_req_mgr_core.h"
|
||||
|
||||
/* Threshold for scheduling delay in ms */
|
||||
#define CAM_WORKQ_SCHEDULE_TIME_THRESHOLD 5
|
||||
|
||||
/* Threshold for execution delay in ms */
|
||||
#define CAM_WORKQ_EXE_TIME_THRESHOLD 10
|
||||
|
||||
/* Flag to create a high priority workq */
|
||||
#define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0)
|
||||
|
||||
|
|
@ -26,13 +32,6 @@
|
|||
*/
|
||||
#define CAM_WORKQ_FLAG_SERIAL (1 << 1)
|
||||
|
||||
/*
|
||||
* Response time threshold in ms beyond which it is considered
|
||||
* as workq scheduling/processing delay.
|
||||
*/
|
||||
#define CAM_WORKQ_RESPONSE_TIME_THRESHOLD 5
|
||||
|
||||
|
||||
/* Task priorities, lower the number higher the priority*/
|
||||
enum crm_task_priority {
|
||||
CRM_TASK_PRIORITY_0,
|
||||
|
|
@ -76,6 +75,7 @@ struct crm_workq_task {
|
|||
* @job : workqueue internal job struct
|
||||
* @lock_bh : lock for task structs
|
||||
* @in_irq : set true if workque can be used in irq context
|
||||
* @workq_scheduled_ts: enqueue time of workq
|
||||
* task -
|
||||
* @lock : Current task's lock handle
|
||||
* @pending_cnt : # of tasks left in queue
|
||||
|
|
@ -150,14 +150,6 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **workq);
|
|||
int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
|
||||
void *priv, int32_t prio);
|
||||
|
||||
/**
|
||||
* cam_req_mgr_thread_switch_delay_detect()
|
||||
* @brief: Detects if workq delay has occurred or not
|
||||
* @timestamp: workq scheduled timestamp
|
||||
*/
|
||||
void cam_req_mgr_thread_switch_delay_detect(
|
||||
ktime_t timestamp);
|
||||
|
||||
/**
|
||||
* cam_req_mgr_workq_get_task()
|
||||
* @brief: Returns empty task pointer for use
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "cam_cci_core.h"
|
||||
#include "cam_cci_dev.h"
|
||||
#include "cam_req_mgr_workq.h"
|
||||
#include "cam_common_util.h"
|
||||
|
||||
static int32_t cam_cci_convert_type_to_num_bytes(
|
||||
enum camera_sensor_i2c_type type)
|
||||
|
|
@ -1498,8 +1499,10 @@ static void cam_cci_write_async_helper(struct work_struct *work)
|
|||
enum cci_i2c_master_t master;
|
||||
struct cam_cci_master_info *cci_master_info;
|
||||
|
||||
cam_req_mgr_thread_switch_delay_detect(
|
||||
write_async->workq_scheduled_ts);
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"CCI workq schedule",
|
||||
write_async->workq_scheduled_ts,
|
||||
CAM_WORKQ_SCHEDULE_TIME_THRESHOLD);
|
||||
cci_dev = write_async->cci_dev;
|
||||
i2c_msg = &write_async->c_ctrl.cfg.cci_i2c_write_cfg;
|
||||
master = write_async->c_ctrl.cci_info->cci_i2c_master;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2018, 2020-2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "cam_sync_util.h"
|
||||
#include "cam_req_mgr_workq.h"
|
||||
#include "cam_common_util.h"
|
||||
|
||||
int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev,
|
||||
long *idx)
|
||||
|
|
@ -294,8 +295,10 @@ void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work)
|
|||
cb_dispatch_work);
|
||||
sync_callback sync_data = cb_info->callback_func;
|
||||
|
||||
cam_req_mgr_thread_switch_delay_detect(
|
||||
cb_info->workq_scheduled_ts);
|
||||
cam_common_util_thread_switch_delay_detect(
|
||||
"CAM-SYNC workq schedule",
|
||||
cb_info->workq_scheduled_ts,
|
||||
CAM_WORKQ_SCHEDULE_TIME_THRESHOLD);
|
||||
sync_data(cb_info->sync_obj, cb_info->status, cb_info->cb_data);
|
||||
|
||||
kfree(cb_info);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
|
|
@ -48,3 +48,27 @@ uint32_t cam_common_util_remove_duplicate_arr(int32_t *arr, uint32_t num)
|
|||
|
||||
return wr_idx;
|
||||
}
|
||||
|
||||
void cam_common_util_thread_switch_delay_detect(
|
||||
const char *token, ktime_t scheduled_time, uint32_t threshold)
|
||||
{
|
||||
uint64_t diff;
|
||||
ktime_t cur_time;
|
||||
struct timespec64 cur_ts;
|
||||
struct timespec64 scheduled_ts;
|
||||
|
||||
cur_time = ktime_get();
|
||||
diff = ktime_ms_delta(cur_time, scheduled_time);
|
||||
|
||||
if (diff > threshold) {
|
||||
scheduled_ts = ktime_to_timespec64(scheduled_time);
|
||||
cur_ts = ktime_to_timespec64(cur_time);
|
||||
CAM_WARN_RATE_LIMIT_CUSTOM(CAM_UTIL, 1, 1,
|
||||
"%s delay detected %ld:%06ld cur %ld:%06ld diff %ld: threshold %d",
|
||||
token, scheduled_ts.tv_sec,
|
||||
scheduled_ts.tv_nsec/NSEC_PER_USEC,
|
||||
cur_ts.tv_sec, cur_ts.tv_nsec/NSEC_PER_USEC,
|
||||
diff, threshold);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CAM_COMMON_UTIL_H_
|
||||
|
|
@ -64,4 +64,17 @@ int cam_common_util_get_string_index(const char **strings,
|
|||
uint32_t cam_common_util_remove_duplicate_arr(int32_t *array,
|
||||
uint32_t num);
|
||||
|
||||
/**
|
||||
* cam_common_util_thread_switch_delay_detect()
|
||||
*
|
||||
* @brief Detect if there is any scheduling delay
|
||||
*
|
||||
* @token: String identifier to print workq name or tasklet
|
||||
* @scheduled_time: Time when workq or tasklet was scheduled
|
||||
* @threshold: Threshold time
|
||||
*
|
||||
*/
|
||||
void cam_common_util_thread_switch_delay_detect(const char *token,
|
||||
ktime_t scheduled_time, uint32_t threshold);
|
||||
|
||||
#endif /* _CAM_COMMON_UTIL_H_ */
|
||||
|
|
|
|||
Loading…
Reference in a new issue