Op 24-09-17 om 16:33 schreef Dmitry Osipenko: > On 04.09.2017 13:48, Maarten Lankhorst wrote: >> By always keeping track of the last commit in plane_state, we know >> whether there is an active update on the plane or not. With that >> information we can reject the fast update, and force the slowpath >> to be used as was originally intended. >> >> We cannot use plane_state->crtc->state here, because this only mentions >> the most recent commit for the crtc, but not the planes that were part >> of it. We specifically care about what the last commit involving this >> plane is, which can only be tracked with a pointer in the plane state. >> >> Changes since v1: >> - Clean up the whole function here, instead of partially earlier. >> - Add mention in the commit message why we need commit in plane_state. >> - Swap plane->state in intel_legacy_cursor_update, instead of >> reassigning all variables. With this commit We know that the cursor >> is not part of any active commits so this hack can be removed. >> >> Cc: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxx> >> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> >> Reviewed-by: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxx> >> Reviewed-by: Daniel Vetter <daniel.vetter@xxxxxxxx> #v1 >> --- >> drivers/gpu/drm/drm_atomic_helper.c | 53 ++++++++++-------------------------- >> drivers/gpu/drm/i915/intel_display.c | 27 +++++++++++------- >> include/drm/drm_plane.h | 5 ++-- >> 3 files changed, 35 insertions(+), 50 deletions(-) >> >> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c >> index c81d46927a74..a2cd432d8b2d 100644 >> --- a/drivers/gpu/drm/drm_atomic_helper.c >> +++ b/drivers/gpu/drm/drm_atomic_helper.c >> @@ -1388,35 +1388,31 @@ int drm_atomic_helper_async_check(struct drm_device *dev, >> { >> struct drm_crtc *crtc; >> struct drm_crtc_state *crtc_state; >> - struct drm_crtc_commit *commit; >> - struct drm_plane *__plane, *plane = NULL; >> - struct drm_plane_state *__plane_state, *plane_state = NULL; >> + struct drm_plane *plane; >> + struct drm_plane_state *old_plane_state, *new_plane_state; >> const struct drm_plane_helper_funcs *funcs; >> - int i, j, n_planes = 0; >> + int i, n_planes = 0; >> >> for_each_new_crtc_in_state(state, crtc, crtc_state, i) { >> if (drm_atomic_crtc_needs_modeset(crtc_state)) >> return -EINVAL; >> } >> >> - for_each_new_plane_in_state(state, __plane, __plane_state, i) { >> + for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) >> n_planes++; >> - plane = __plane; >> - plane_state = __plane_state; >> - } >> >> /* FIXME: we support only single plane updates for now */ >> - if (!plane || n_planes != 1) >> + if (n_planes != 1) >> return -EINVAL; >> >> - if (!plane_state->crtc) >> + if (!new_plane_state->crtc) >> return -EINVAL; >> > Hello, > > It looks like a NULL-checking of new_plane_state is missed here. > > [ 70.138947] [<c03dd670>] (drm_atomic_helper_async_check) from [<c03e0424>] > (drm_atomic_helper_check+0x4c/0x64) > [ 70.138958] [<c03e0424>] (drm_atomic_helper_check) from [<c03fb6d4>] > (drm_atomic_check_only+0x2f4/0x56c) > [ 70.138969] [<c03fb6d4>] (drm_atomic_check_only) from [<c03fb95c>] > (drm_atomic_commit+0x10/0x50) > [ 70.138979] [<c03fb95c>] (drm_atomic_commit) from [<c03dde50>] > (drm_atomic_helper_update_plane+0xf0/0x100) > [ 70.138991] [<c03dde50>] (drm_atomic_helper_update_plane) from [<c0403548>] > (__setplane_internal+0x178/0x214) > [ 70.139003] [<c0403548>] (__setplane_internal) from [<c04036fc>] > (drm_mode_cursor_universal+0x118/0x1a8) > [ 70.139014] [<c04036fc>] (drm_mode_cursor_universal) from [<c0403900>] > (drm_mode_cursor_common+0x174/0x1ec) > [ 70.139026] [<c0403900>] (drm_mode_cursor_common) from [<c0403fa4>] > (drm_mode_cursor_ioctl+0x58/0x60) > [ 70.139036] [<c0403fa4>] (drm_mode_cursor_ioctl) from [<c03eb0b4>] > (drm_ioctl+0x198/0x368) > [ 70.139047] [<c03eb0b4>] (drm_ioctl) from [<c015fffc>] (do_vfs_ioctl+0x9c/0x8f0) > [ 70.139058] [<c015fffc>] (do_vfs_ioctl) from [<c0160884>] (SyS_ioctl+0x34/0x5c) > [ 70.139071] [<c0160884>] (SyS_ioctl) from [<c000f900>] > (ret_fast_syscall+0x0/0x48) > > It's triggered by Tegra DRM driver on Xorg's startup. I also should notice that > currently Tegra DRM doesn't have a working HW cursor, I'm going to send out > Tegra cursor patches sometime soon. Oops.. I messed up there.. for_each_new_plane_in_state overwrites the state internally.. ----->8----- for_each_oldnew_plane_in_state overwrites the iterator values internally, so we cannot rely on it being set to the last valid plane. This was causing a NULL pointer deref when someone tries to use the code. Save the plane and use the accessor functions to pull out the relevant plane state. Cc: Dmitry Osipenko <digetx@xxxxxxxxx> Fixes: 669c9215afea ("drm/atomic: Make async plane update checks work as intended, v2.") Signed-off-by: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> --- diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 32fb61169b4f..8573feaea8c0 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1388,23 +1388,30 @@ int drm_atomic_helper_async_check(struct drm_device *dev, { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - struct drm_plane *plane; + struct drm_plane *plane = NULL, *__plane; struct drm_plane_state *old_plane_state, *new_plane_state; const struct drm_plane_helper_funcs *funcs; - int i, n_planes = 0; + int i; for_each_new_crtc_in_state(state, crtc, crtc_state, i) { if (drm_atomic_crtc_needs_modeset(crtc_state)) return -EINVAL; } - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) - n_planes++; + for_each_new_plane_in_state(state, __plane, new_plane_state, i) { + /* FIXME: we support only single plane updates for now */ + if (plane) + return -EINVAL; + + plane = __plane; + } - /* FIXME: we support only single plane updates for now */ - if (n_planes != 1) + if (!plane) return -EINVAL; + old_plane_state = drm_atomic_get_old_plane_state(state, plane); + new_plane_state = drm_atomic_get_new_plane_state(state, plane); + if (!new_plane_state->crtc) return -EINVAL; -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html