diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-11-19 12:38:08 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-11-19 20:35:20 -0500 |
commit | f52b69f1ecfdd7ef6867a257620258c09e569552 (patch) | |
tree | 743137d6d11bd5a9ed8bba2484de30c5f630944c /drivers/gpu/drm/drm_atomic_helper.c | |
parent | 6f75cea66c8dd043ced282016b21a639af176642 (diff) |
drm/atomic: Don't overrun the connector array when hotplugging
Yet another fallout from not considering DP MST hotplug. With the
previous patches we have stable indices, but it might still happen
that a connector gets added between when we allocate the array and
when we actually add a connector. Especially when we back off due to
ww mutex contention or similar issues.
So store the sizes of the arrays in struct drm_atomic_state and double
check them. We don't really care about races except that we want to
use a consistent value, so ACCESS_ONCE is all we need. And if we
indeed notice that we'd overrun the array then just give up and
restart the entire ioctl.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 23 |
1 files changed, 8 insertions, 15 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0cd054615920..99095ef147ef 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -249,7 +249,6 @@ static int | |||
249 | mode_fixup(struct drm_atomic_state *state) | 249 | mode_fixup(struct drm_atomic_state *state) |
250 | { | 250 | { |
251 | int ncrtcs = state->dev->mode_config.num_crtc; | 251 | int ncrtcs = state->dev->mode_config.num_crtc; |
252 | int nconnectors = state->dev->mode_config.num_connector; | ||
253 | struct drm_crtc_state *crtc_state; | 252 | struct drm_crtc_state *crtc_state; |
254 | struct drm_connector_state *conn_state; | 253 | struct drm_connector_state *conn_state; |
255 | int i; | 254 | int i; |
@@ -264,7 +263,7 @@ mode_fixup(struct drm_atomic_state *state) | |||
264 | drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode); | 263 | drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode); |
265 | } | 264 | } |
266 | 265 | ||
267 | for (i = 0; i < nconnectors; i++) { | 266 | for (i = 0; i < state->num_connector; i++) { |
268 | struct drm_encoder_helper_funcs *funcs; | 267 | struct drm_encoder_helper_funcs *funcs; |
269 | struct drm_encoder *encoder; | 268 | struct drm_encoder *encoder; |
270 | 269 | ||
@@ -336,7 +335,6 @@ drm_atomic_helper_check_prepare(struct drm_device *dev, | |||
336 | struct drm_atomic_state *state) | 335 | struct drm_atomic_state *state) |
337 | { | 336 | { |
338 | int ncrtcs = dev->mode_config.num_crtc; | 337 | int ncrtcs = dev->mode_config.num_crtc; |
339 | int nconnectors = dev->mode_config.num_connector; | ||
340 | struct drm_crtc *crtc; | 338 | struct drm_crtc *crtc; |
341 | struct drm_crtc_state *crtc_state; | 339 | struct drm_crtc_state *crtc_state; |
342 | int i, ret; | 340 | int i, ret; |
@@ -361,7 +359,7 @@ drm_atomic_helper_check_prepare(struct drm_device *dev, | |||
361 | } | 359 | } |
362 | } | 360 | } |
363 | 361 | ||
364 | for (i = 0; i < nconnectors; i++) { | 362 | for (i = 0; i < state->num_connector; i++) { |
365 | /* | 363 | /* |
366 | * This only sets crtc->mode_changed for routing changes, | 364 | * This only sets crtc->mode_changed for routing changes, |
367 | * drivers must set crtc->mode_changed themselves when connector | 365 | * drivers must set crtc->mode_changed themselves when connector |
@@ -485,10 +483,9 @@ static void | |||
485 | disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | 483 | disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) |
486 | { | 484 | { |
487 | int ncrtcs = old_state->dev->mode_config.num_crtc; | 485 | int ncrtcs = old_state->dev->mode_config.num_crtc; |
488 | int nconnectors = old_state->dev->mode_config.num_connector; | ||
489 | int i; | 486 | int i; |
490 | 487 | ||
491 | for (i = 0; i < nconnectors; i++) { | 488 | for (i = 0; i < old_state->num_connector; i++) { |
492 | struct drm_connector_state *old_conn_state; | 489 | struct drm_connector_state *old_conn_state; |
493 | struct drm_connector *connector; | 490 | struct drm_connector *connector; |
494 | struct drm_encoder_helper_funcs *funcs; | 491 | struct drm_encoder_helper_funcs *funcs; |
@@ -553,12 +550,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
553 | static void | 550 | static void |
554 | set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) | 551 | set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) |
555 | { | 552 | { |
556 | int nconnectors = dev->mode_config.num_connector; | ||
557 | int ncrtcs = old_state->dev->mode_config.num_crtc; | 553 | int ncrtcs = old_state->dev->mode_config.num_crtc; |
558 | int i; | 554 | int i; |
559 | 555 | ||
560 | /* clear out existing links */ | 556 | /* clear out existing links */ |
561 | for (i = 0; i < nconnectors; i++) { | 557 | for (i = 0; i < old_state->num_connector; i++) { |
562 | struct drm_connector *connector; | 558 | struct drm_connector *connector; |
563 | 559 | ||
564 | connector = old_state->connectors[i]; | 560 | connector = old_state->connectors[i]; |
@@ -573,7 +569,7 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
573 | } | 569 | } |
574 | 570 | ||
575 | /* set new links */ | 571 | /* set new links */ |
576 | for (i = 0; i < nconnectors; i++) { | 572 | for (i = 0; i < old_state->num_connector; i++) { |
577 | struct drm_connector *connector; | 573 | struct drm_connector *connector; |
578 | 574 | ||
579 | connector = old_state->connectors[i]; | 575 | connector = old_state->connectors[i]; |
@@ -608,7 +604,6 @@ static void | |||
608 | crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) | 604 | crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) |
609 | { | 605 | { |
610 | int ncrtcs = old_state->dev->mode_config.num_crtc; | 606 | int ncrtcs = old_state->dev->mode_config.num_crtc; |
611 | int nconnectors = old_state->dev->mode_config.num_connector; | ||
612 | int i; | 607 | int i; |
613 | 608 | ||
614 | for (i = 0; i < ncrtcs; i++) { | 609 | for (i = 0; i < ncrtcs; i++) { |
@@ -626,7 +621,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) | |||
626 | funcs->mode_set_nofb(crtc); | 621 | funcs->mode_set_nofb(crtc); |
627 | } | 622 | } |
628 | 623 | ||
629 | for (i = 0; i < nconnectors; i++) { | 624 | for (i = 0; i < old_state->num_connector; i++) { |
630 | struct drm_connector *connector; | 625 | struct drm_connector *connector; |
631 | struct drm_crtc_state *new_crtc_state; | 626 | struct drm_crtc_state *new_crtc_state; |
632 | struct drm_encoder_helper_funcs *funcs; | 627 | struct drm_encoder_helper_funcs *funcs; |
@@ -687,7 +682,6 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, | |||
687 | struct drm_atomic_state *old_state) | 682 | struct drm_atomic_state *old_state) |
688 | { | 683 | { |
689 | int ncrtcs = old_state->dev->mode_config.num_crtc; | 684 | int ncrtcs = old_state->dev->mode_config.num_crtc; |
690 | int nconnectors = old_state->dev->mode_config.num_connector; | ||
691 | int i; | 685 | int i; |
692 | 686 | ||
693 | for (i = 0; i < ncrtcs; i++) { | 687 | for (i = 0; i < ncrtcs; i++) { |
@@ -706,7 +700,7 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, | |||
706 | funcs->commit(crtc); | 700 | funcs->commit(crtc); |
707 | } | 701 | } |
708 | 702 | ||
709 | for (i = 0; i < nconnectors; i++) { | 703 | for (i = 0; i < old_state->num_connector; i++) { |
710 | struct drm_connector *connector; | 704 | struct drm_connector *connector; |
711 | struct drm_encoder_helper_funcs *funcs; | 705 | struct drm_encoder_helper_funcs *funcs; |
712 | struct drm_encoder *encoder; | 706 | struct drm_encoder *encoder; |
@@ -1304,7 +1298,6 @@ static int update_output_state(struct drm_atomic_state *state, | |||
1304 | { | 1298 | { |
1305 | struct drm_device *dev = set->crtc->dev; | 1299 | struct drm_device *dev = set->crtc->dev; |
1306 | struct drm_connector_state *conn_state; | 1300 | struct drm_connector_state *conn_state; |
1307 | int nconnectors = state->dev->mode_config.num_connector; | ||
1308 | int ncrtcs = state->dev->mode_config.num_crtc; | 1301 | int ncrtcs = state->dev->mode_config.num_crtc; |
1309 | int ret, i, j; | 1302 | int ret, i, j; |
1310 | 1303 | ||
@@ -1333,7 +1326,7 @@ static int update_output_state(struct drm_atomic_state *state, | |||
1333 | } | 1326 | } |
1334 | 1327 | ||
1335 | /* Then recompute connector->crtc links and crtc enabling state. */ | 1328 | /* Then recompute connector->crtc links and crtc enabling state. */ |
1336 | for (i = 0; i < nconnectors; i++) { | 1329 | for (i = 0; i < state->num_connector; i++) { |
1337 | struct drm_connector *connector; | 1330 | struct drm_connector *connector; |
1338 | 1331 | ||
1339 | connector = state->connectors[i]; | 1332 | connector = state->connectors[i]; |