summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMidas Chien <midaschieh@google.com>2021-12-09 18:01:39 +0800
committerMidas Chien <midaschieh@google.com>2021-12-16 00:38:04 +0800
commitd9eabf5eb9a6072b1120bb78c11ba882658f159e (patch)
tree0022abe51b7d1c96994364df0b8257b4cbe4f58e
parent066b5f0309aa57a8fb40a1ff68912a4b4ce3ba9e (diff)
downloaddisplay-d9eabf5eb9a6072b1120bb78c11ba882658f159e.tar.gz
drm: samsung: add lock when dumping dpu event logs
There is race condition between read and write dpu event logs. Add lock to protect dpu event log content to avoid race issue. Bug: 209878019 Test: dump dpu event logs continuously and do some operators at same time, including on/off, video, camera, chrome, youtube Test: simulate underrun to dump dpu event logs automatically Change-Id: Idcd77c6f2c230557be4f0851d4bcd55bb6d115df Signed-off-by: Midas Chien <midaschieh@google.com>
-rw-r--r--samsung/exynos_drm_debug.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/samsung/exynos_drm_debug.c b/samsung/exynos_drm_debug.c
index 867e3db..bef8e95 100644
--- a/samsung/exynos_drm_debug.c
+++ b/samsung/exynos_drm_debug.c
@@ -144,10 +144,10 @@ void DPU_EVENT_LOG(enum dpu_event_type type, int index, void *priv)
spin_lock_irqsave(&decon->d.event_lock, flags);
idx = atomic_inc_return(&decon->d.event_log_idx) % dpu_event_log_max;
log = &decon->d.event_log[idx];
+ log->type = DPU_EVT_NONE;
spin_unlock_irqrestore(&decon->d.event_lock, flags);
log->time = ktime_get();
- log->type = type;
switch (type) {
case DPU_EVT_DPP_FRAMEDONE:
@@ -265,6 +265,8 @@ void DPU_EVENT_LOG(enum dpu_event_type type, int index, void *priv)
default:
break;
}
+
+ log->type = type;
}
/*
@@ -294,9 +296,9 @@ void DPU_EVENT_LOG_ATOMIC_COMMIT(int index)
spin_lock_irqsave(&decon->d.event_lock, flags);
idx = atomic_inc_return(&decon->d.event_log_idx) % dpu_event_log_max;
log = &decon->d.event_log[idx];
+ log->type = DPU_EVT_NONE;
spin_unlock_irqrestore(&decon->d.event_lock, flags);
- log->type = DPU_EVT_ATOMIC_COMMIT;
log->time = ktime_get();
decon->d.auto_refresh_frames = 0;
@@ -313,6 +315,8 @@ void DPU_EVENT_LOG_ATOMIC_COMMIT(int index)
decon->dpp[dpp_ch]->dbg_dma_addr;
}
}
+
+ log->type = DPU_EVT_ATOMIC_COMMIT;
}
extern void *return_address(unsigned int);
@@ -347,9 +351,9 @@ DPU_EVENT_LOG_CMD(struct dsim_device *dsim, u8 type, u8 d0, u16 len)
spin_lock_irqsave(&decon->d.event_lock, flags);
idx = atomic_inc_return(&decon->d.event_log_idx) % dpu_event_log_max;
log = &decon->d.event_log[idx];
+ log->type = DPU_EVT_NONE;
spin_unlock_irqrestore(&decon->d.event_lock, flags);
- log->type = DPU_EVT_DSIM_COMMAND;
log->time = ktime_get();
log->data.cmd.id = type;
@@ -359,6 +363,8 @@ DPU_EVENT_LOG_CMD(struct dsim_device *dsim, u8 type, u8 d0, u16 len)
for (i = 0; i < DPU_CALLSTACK_MAX; i++)
log->data.cmd.caller[i] =
(void *)((size_t)return_address(i + 1));
+
+ log->type = DPU_EVT_DSIM_COMMAND;
}
static void dpu_print_log_atomic(struct dpu_log_atomic *atomic,
@@ -378,6 +384,12 @@ static void dpu_print_log_atomic(struct dpu_log_atomic *atomic,
if (win->state == DPU_WIN_STATE_DISABLED)
continue;
+ if (win->state < DPU_WIN_STATE_DISABLED ||
+ win->state > DPU_WIN_STATE_BUFFER) {
+ pr_warn("%s: invalid win state %d\n", __func__, win->state);
+ continue;
+ }
+
fmt = dpu_find_fmt_info(win->format);
len = scnprintf(buf, sizeof(buf),
@@ -597,15 +609,18 @@ static void dpu_event_log_print(const struct decon_device *decon, struct drm_pri
size_t max_logs, enum dpu_event_condition condition)
{
int idx = atomic_read(&decon->d.event_log_idx);
- struct dpu_log *log;
+ struct decon_device *decon_dev = (struct decon_device *)decon;
+ struct dpu_log dump_log;
+ struct dpu_log *log = &dump_log;
int latest = idx % dpu_event_log_max;
struct timespec64 ts;
const char *str_comp;
char buf[LOG_BUF_SIZE];
const struct dpu_fmt *fmt;
int len;
+ unsigned long flags;
- if (IS_ERR_OR_NULL(decon->d.event_log))
+ if (IS_ERR_OR_NULL(decon_dev->d.event_log))
return;
drm_printf(p, "----------------------------------------------------\n");
@@ -625,8 +640,10 @@ static void dpu_event_log_print(const struct decon_device *decon, struct drm_pri
if (++idx >= dpu_event_log_max)
idx = 0;
- /* Seek a index */
- log = &decon->d.event_log[idx];
+ /* Seek a index and copy log for dump */
+ spin_lock_irqsave(&decon_dev->d.event_lock, flags);
+ memcpy(&dump_log, &decon_dev->d.event_log[idx], sizeof(dump_log));
+ spin_unlock_irqrestore(&decon_dev->d.event_lock, flags);
if (is_skip_dpu_event_dump(log->type, condition))
continue;