summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Salido <salidoa@google.com>2023-03-23 20:00:31 -0700
committerTreeHugger Robot <treehugger-gerrit@google.com>2023-03-29 05:38:47 +0000
commitd8489ee7e1f513aac18694effe0b969f0a0bd60e (patch)
tree81f929169de6fdf5c1566a2fa9d59ce3706ab00b
parent0e3483072e06933dbc2266112d739bf36b324e67 (diff)
downloaddisplay-d8489ee7e1f513aac18694effe0b969f0a0bd60e.tar.gz
drm: samsung: move commit work to crtc state
The private object is global for all devices so it's possible that commits on different crtc could cause previous private objects to be removed and cause use-after-free issues. To avoid this, move commit work to happen within crtc. Since we are already using per crtc/decon worker, it won't be possible to get ahead in this case. Bug: 263674548 Test: perform empty atomic commits after non-blocking one on crtc Change-Id: Ie648a2e7069290cd3168ed2d847b97e176f8a2ee Signed-off-by: Adrian Salido <salidoa@google.com>
-rw-r--r--samsung/exynos_drm_drv.c28
-rw-r--r--samsung/exynos_drm_drv.h5
2 files changed, 11 insertions, 22 deletions
diff --git a/samsung/exynos_drm_drv.c b/samsung/exynos_drm_drv.c
index 5405fe7..f28fb15 100644
--- a/samsung/exynos_drm_drv.c
+++ b/samsung/exynos_drm_drv.c
@@ -515,10 +515,11 @@ static void commit_tail(struct drm_atomic_state *old_state)
static void commit_kthread_work(struct kthread_work *work)
{
- struct exynos_drm_priv_state *exynos_priv_state =
- container_of(work, struct exynos_drm_priv_state, commit_work);
- struct drm_atomic_state *old_state = exynos_priv_state->old_state;
+ struct exynos_drm_crtc_state *old_exynos_crtc_state =
+ container_of(work, struct exynos_drm_crtc_state, commit_work);
+ struct drm_atomic_state *old_state = old_exynos_crtc_state->base.state;
+ BUG_ON(!old_state);
commit_tail(old_state);
}
@@ -530,8 +531,7 @@ static void commit_work(struct work_struct *work)
commit_tail(old_state);
}
-static void exynos_atomic_queue_work(struct drm_atomic_state *old_state, bool nonblock,
- struct kthread_work *work)
+static void exynos_atomic_queue_work(struct drm_atomic_state *old_state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
@@ -544,10 +544,10 @@ static void exynos_atomic_queue_work(struct drm_atomic_state *old_state, bool no
* TODO: can work be split per display?
*/
for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
- struct exynos_drm_crtc *exynos_crtc =
- container_of(crtc, struct exynos_drm_crtc, base);
- struct decon_device *decon = exynos_crtc->ctx;
+ struct decon_device *decon = crtc_to_decon(crtc);
+ struct kthread_work *work = &to_exynos_crtc_state(old_crtc_state)->commit_work;
+ kthread_init_work(work, commit_kthread_work);
kthread_queue_work(&decon->worker, work);
return;
@@ -560,7 +560,6 @@ static void exynos_atomic_queue_work(struct drm_atomic_state *old_state, bool no
int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock)
{
- struct exynos_drm_priv_state *exynos_priv_state;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
int i, ret;
@@ -590,15 +589,6 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
if (ret)
goto err;
- exynos_priv_state = exynos_drm_get_priv_state(state);
- if (IS_ERR(exynos_priv_state)) {
- ret = PTR_ERR(exynos_priv_state);
- goto err;
- }
-
- kthread_init_work(&exynos_priv_state->commit_work, commit_kthread_work);
- exynos_priv_state->old_state = state;
-
ret = drm_atomic_helper_prepare_planes(dev, state);
if (ret)
goto err;
@@ -639,7 +629,7 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
if (!nonblock)
commit_tail(state);
else
- exynos_atomic_queue_work(state, nonblock, &exynos_priv_state->commit_work);
+ exynos_atomic_queue_work(state);
err:
DPU_ATRACE_END("exynos_atomic_commit");
diff --git a/samsung/exynos_drm_drv.h b/samsung/exynos_drm_drv.h
index 88ea0b8..5e03ef9 100644
--- a/samsung/exynos_drm_drv.h
+++ b/samsung/exynos_drm_drv.h
@@ -278,6 +278,8 @@ struct exynos_drm_crtc_state {
struct drm_rect partial_region;
struct drm_property_blob *partial;
bool needs_reconfigure;
+
+ struct kthread_work commit_work;
};
static inline struct exynos_drm_crtc_state *
@@ -336,9 +338,6 @@ struct exynos_drm_pending_histogram_event {
struct exynos_drm_priv_state {
struct drm_private_state base;
- struct drm_atomic_state *old_state;
- struct kthread_work commit_work;
-
unsigned int available_win_mask;
};