Skip to content

Commit 0853695

Browse files
ickledanvet
authored andcommitted
drm: Add reference counting to drm_atomic_state
drm_atomic_state has a complicated single owner model that tracks the single reference from allocation through to destruction on another thread - or perhaps on a local error path. We can simplify this tracking by using reference counting (at a cost of a few more atomics). This is even more beneficial when the lifetime of the state becomes more convoluted than being passed to a single worker thread for the commit. v2: Double check !intel atomic_commit functions for missing gets v3: Update kerneldocs Signed-off-by: Chris Wilson <[email protected]> Cc: Daniel Vetter <[email protected]> Cc: [email protected] Reviewed-by: Eric Engestrom <[email protected]> Reviewed-by: Sean Paul <[email protected]> Signed-off-by: Daniel Vetter <[email protected]> Link: http://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 1dfdb0e commit 0853695

File tree

18 files changed

+102
-131
lines changed

18 files changed

+102
-131
lines changed

drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ atmel_hlcdc_dc_atomic_complete(struct atmel_hlcdc_dc_commit *commit)
464464

465465
drm_atomic_helper_cleanup_planes(dev, old_state);
466466

467-
drm_atomic_state_free(old_state);
467+
drm_atomic_state_put(old_state);
468468

469469
/* Complete the commit, wake up any waiter. */
470470
spin_lock(&dc->commit.wait.lock);
@@ -521,6 +521,7 @@ static int atmel_hlcdc_dc_atomic_commit(struct drm_device *dev,
521521
/* Swap the state, this is the point of no return. */
522522
drm_atomic_helper_swap_state(state, true);
523523

524+
drm_atomic_state_get(state);
524525
if (async)
525526
queue_work(dc->wq, &commit->work);
526527
else

drivers/gpu/drm/drm_atomic.c

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ EXPORT_SYMBOL(drm_atomic_state_default_release);
7474
int
7575
drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
7676
{
77+
kref_init(&state->ref);
78+
7779
/* TODO legacy paths should maybe do a better job about
7880
* setting this appropriately?
7981
*/
@@ -215,22 +217,16 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
215217
EXPORT_SYMBOL(drm_atomic_state_clear);
216218

217219
/**
218-
* drm_atomic_state_free - free all memory for an atomic state
219-
* @state: atomic state to deallocate
220+
* __drm_atomic_state_free - free all memory for an atomic state
221+
* @ref: This atomic state to deallocate
220222
*
221223
* This frees all memory associated with an atomic state, including all the
222224
* per-object state for planes, crtcs and connectors.
223225
*/
224-
void drm_atomic_state_free(struct drm_atomic_state *state)
226+
void __drm_atomic_state_free(struct kref *ref)
225227
{
226-
struct drm_device *dev;
227-
struct drm_mode_config *config;
228-
229-
if (!state)
230-
return;
231-
232-
dev = state->dev;
233-
config = &dev->mode_config;
228+
struct drm_atomic_state *state = container_of(ref, typeof(*state), ref);
229+
struct drm_mode_config *config = &state->dev->mode_config;
234230

235231
drm_atomic_state_clear(state);
236232

@@ -243,7 +239,7 @@ void drm_atomic_state_free(struct drm_atomic_state *state)
243239
kfree(state);
244240
}
245241
}
246-
EXPORT_SYMBOL(drm_atomic_state_free);
242+
EXPORT_SYMBOL(__drm_atomic_state_free);
247243

248244
/**
249245
* drm_atomic_get_crtc_state - get crtc state
@@ -1742,7 +1738,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
17421738
if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
17431739
/*
17441740
* Unlike commit, check_only does not clean up state.
1745-
* Below we call drm_atomic_state_free for it.
1741+
* Below we call drm_atomic_state_put for it.
17461742
*/
17471743
ret = drm_atomic_check_only(state);
17481744
} else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
@@ -1775,8 +1771,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
17751771
goto retry;
17761772
}
17771773

1778-
if (ret || arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
1779-
drm_atomic_state_free(state);
1774+
drm_atomic_state_put(state);
17801775

17811776
drm_modeset_drop_locks(&ctx);
17821777
drm_modeset_acquire_fini(&ctx);

drivers/gpu/drm/drm_atomic_helper.c

Lines changed: 24 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ static void commit_tail(struct drm_atomic_state *state)
12081208

12091209
drm_atomic_helper_commit_cleanup_done(state);
12101210

1211-
drm_atomic_state_free(state);
1211+
drm_atomic_state_put(state);
12121212
}
12131213

12141214
static void commit_work(struct work_struct *work)
@@ -1290,6 +1290,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
12901290
* make sure work items don't artifically stall on each another.
12911291
*/
12921292

1293+
drm_atomic_state_get(state);
12931294
if (nonblock)
12941295
queue_work(system_unbound_wq, &state->commit_work);
12951296
else
@@ -1591,7 +1592,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
15911592
*
15921593
* This signals completion of the atomic update @state, including any cleanup
15931594
* work. If used, it must be called right before calling
1594-
* drm_atomic_state_free().
1595+
* drm_atomic_state_put().
15951596
*
15961597
* This is part of the atomic helper support for nonblocking commits, see
15971598
* drm_atomic_helper_setup_commit() for an overview.
@@ -2114,18 +2115,13 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
21142115
state->legacy_cursor_update = true;
21152116

21162117
ret = drm_atomic_commit(state);
2117-
if (ret != 0)
2118-
goto fail;
2119-
2120-
/* Driver takes ownership of state on successful commit. */
2121-
return 0;
21222118
fail:
21232119
if (ret == -EDEADLK)
21242120
goto backoff;
21252121

2126-
drm_atomic_state_free(state);
2127-
2122+
drm_atomic_state_put(state);
21282123
return ret;
2124+
21292125
backoff:
21302126
drm_atomic_state_clear(state);
21312127
drm_atomic_legacy_backoff(state);
@@ -2187,18 +2183,13 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
21872183
goto fail;
21882184

21892185
ret = drm_atomic_commit(state);
2190-
if (ret != 0)
2191-
goto fail;
2192-
2193-
/* Driver takes ownership of state on successful commit. */
2194-
return 0;
21952186
fail:
21962187
if (ret == -EDEADLK)
21972188
goto backoff;
21982189

2199-
drm_atomic_state_free(state);
2200-
2190+
drm_atomic_state_put(state);
22012191
return ret;
2192+
22022193
backoff:
22032194
drm_atomic_state_clear(state);
22042195
drm_atomic_legacy_backoff(state);
@@ -2327,18 +2318,13 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
23272318
goto fail;
23282319

23292320
ret = drm_atomic_commit(state);
2330-
if (ret != 0)
2331-
goto fail;
2332-
2333-
/* Driver takes ownership of state on successful commit. */
2334-
return 0;
23352321
fail:
23362322
if (ret == -EDEADLK)
23372323
goto backoff;
23382324

2339-
drm_atomic_state_free(state);
2340-
2325+
drm_atomic_state_put(state);
23412326
return ret;
2327+
23422328
backoff:
23432329
drm_atomic_state_clear(state);
23442330
drm_atomic_legacy_backoff(state);
@@ -2480,11 +2466,8 @@ int drm_atomic_helper_disable_all(struct drm_device *dev,
24802466
}
24812467

24822468
err = drm_atomic_commit(state);
2483-
24842469
free:
2485-
if (err < 0)
2486-
drm_atomic_state_free(state);
2487-
2470+
drm_atomic_state_put(state);
24882471
return err;
24892472
}
24902473
EXPORT_SYMBOL(drm_atomic_helper_disable_all);
@@ -2535,7 +2518,7 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
25352518

25362519
err = drm_atomic_helper_disable_all(dev, &ctx);
25372520
if (err < 0) {
2538-
drm_atomic_state_free(state);
2521+
drm_atomic_state_put(state);
25392522
state = ERR_PTR(err);
25402523
goto unlock;
25412524
}
@@ -2624,18 +2607,13 @@ drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
26242607
goto fail;
26252608

26262609
ret = drm_atomic_commit(state);
2627-
if (ret != 0)
2628-
goto fail;
2629-
2630-
/* Driver takes ownership of state on successful commit. */
2631-
return 0;
26322610
fail:
26332611
if (ret == -EDEADLK)
26342612
goto backoff;
26352613

2636-
drm_atomic_state_free(state);
2637-
2614+
drm_atomic_state_put(state);
26382615
return ret;
2616+
26392617
backoff:
26402618
drm_atomic_state_clear(state);
26412619
drm_atomic_legacy_backoff(state);
@@ -2684,18 +2662,13 @@ drm_atomic_helper_plane_set_property(struct drm_plane *plane,
26842662
goto fail;
26852663

26862664
ret = drm_atomic_commit(state);
2687-
if (ret != 0)
2688-
goto fail;
2689-
2690-
/* Driver takes ownership of state on successful commit. */
2691-
return 0;
26922665
fail:
26932666
if (ret == -EDEADLK)
26942667
goto backoff;
26952668

2696-
drm_atomic_state_free(state);
2697-
2669+
drm_atomic_state_put(state);
26982670
return ret;
2671+
26992672
backoff:
27002673
drm_atomic_state_clear(state);
27012674
drm_atomic_legacy_backoff(state);
@@ -2744,18 +2717,13 @@ drm_atomic_helper_connector_set_property(struct drm_connector *connector,
27442717
goto fail;
27452718

27462719
ret = drm_atomic_commit(state);
2747-
if (ret != 0)
2748-
goto fail;
2749-
2750-
/* Driver takes ownership of state on successful commit. */
2751-
return 0;
27522720
fail:
27532721
if (ret == -EDEADLK)
27542722
goto backoff;
27552723

2756-
drm_atomic_state_free(state);
2757-
2724+
drm_atomic_state_put(state);
27582725
return ret;
2726+
27592727
backoff:
27602728
drm_atomic_state_clear(state);
27612729
drm_atomic_legacy_backoff(state);
@@ -2828,18 +2796,13 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
28282796
}
28292797

28302798
ret = drm_atomic_nonblocking_commit(state);
2831-
if (ret != 0)
2832-
goto fail;
2833-
2834-
/* Driver takes ownership of state on successful commit. */
2835-
return 0;
28362799
fail:
28372800
if (ret == -EDEADLK)
28382801
goto backoff;
28392802

2840-
drm_atomic_state_free(state);
2841-
2803+
drm_atomic_state_put(state);
28422804
return ret;
2805+
28432806
backoff:
28442807
drm_atomic_state_clear(state);
28452808
drm_atomic_legacy_backoff(state);
@@ -2915,19 +2878,14 @@ int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
29152878
crtc_state->active = active;
29162879

29172880
ret = drm_atomic_commit(state);
2918-
if (ret != 0)
2919-
goto fail;
2920-
2921-
/* Driver takes ownership of state on successful commit. */
2922-
return 0;
29232881
fail:
29242882
if (ret == -EDEADLK)
29252883
goto backoff;
29262884

29272885
connector->dpms = old_mode;
2928-
drm_atomic_state_free(state);
2929-
2886+
drm_atomic_state_put(state);
29302887
return ret;
2888+
29312889
backoff:
29322890
drm_atomic_state_clear(state);
29332891
drm_atomic_legacy_backoff(state);
@@ -3334,7 +3292,7 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev,
33343292

33353293
free:
33363294
if (err < 0) {
3337-
drm_atomic_state_free(state);
3295+
drm_atomic_state_put(state);
33383296
state = ERR_PTR(err);
33393297
}
33403298

@@ -3449,22 +3407,14 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
34493407
goto fail;
34503408

34513409
ret = drm_atomic_commit(state);
3452-
if (ret)
3453-
goto fail;
3454-
3455-
/* Driver takes ownership of state on successful commit. */
3456-
3457-
drm_property_unreference_blob(blob);
3458-
3459-
return 0;
34603410
fail:
34613411
if (ret == -EDEADLK)
34623412
goto backoff;
34633413

3464-
drm_atomic_state_free(state);
3414+
drm_atomic_state_put(state);
34653415
drm_property_unreference_blob(blob);
3466-
34673416
return ret;
3417+
34683418
backoff:
34693419
drm_atomic_state_clear(state);
34703420
drm_atomic_legacy_backoff(state);

drivers/gpu/drm/drm_fb_helper.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
367367
if (ret == -EDEADLK)
368368
goto backoff;
369369

370-
if (ret != 0)
371-
drm_atomic_state_free(state);
372-
370+
drm_atomic_state_put(state);
373371
return ret;
374372

375373
backoff:
@@ -1361,16 +1359,13 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
13611359
info->var.xoffset = var->xoffset;
13621360
info->var.yoffset = var->yoffset;
13631361

1364-
13651362
fail:
13661363
drm_atomic_clean_old_fb(dev, plane_mask, ret);
13671364

13681365
if (ret == -EDEADLK)
13691366
goto backoff;
13701367

1371-
if (ret != 0)
1372-
drm_atomic_state_free(state);
1373-
1368+
drm_atomic_state_put(state);
13741369
return ret;
13751370

13761371
backoff:

drivers/gpu/drm/exynos/exynos_drm_drv.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
6969

7070
drm_atomic_helper_cleanup_planes(dev, state);
7171

72-
drm_atomic_state_free(state);
72+
drm_atomic_state_put(state);
7373

7474
spin_lock(&priv->lock);
7575
priv->pending &= ~commit->crtcs;
@@ -254,6 +254,7 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
254254

255255
drm_atomic_helper_swap_state(state, true);
256256

257+
drm_atomic_state_get(state);
257258
if (nonblock)
258259
schedule_work(&commit->work);
259260
else

drivers/gpu/drm/i915/i915_debugfs.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3941,10 +3941,9 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv,
39413941

39423942
ret = drm_atomic_commit(state);
39433943
out:
3944-
drm_modeset_unlock_all(dev);
39453944
WARN(ret, "Toggling workaround to %i returns %i\n", enable, ret);
3946-
if (ret)
3947-
drm_atomic_state_free(state);
3945+
drm_modeset_unlock_all(dev);
3946+
drm_atomic_state_put(state);
39483947
}
39493948

39503949
static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,

0 commit comments

Comments
 (0)