Merge tag 'drm-fixes-2018-10-20-1' of git://anongit.freedesktop.org/drm/drm
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 20 Oct 2018 07:23:12 +0000 (09:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 20 Oct 2018 07:23:12 +0000 (09:23 +0200)
Dave writes:
  "drm fixes for 4.19 final (part 2)

   Looked like two stragglers snuck in, one very urgent the pageflipping
   was missing a reference that could result in a GPF on non-i915
   drivers, the other is an overflow in the sun4i dotclock calcs
   resulting in a mode not getting set."

* tag 'drm-fixes-2018-10-20-1' of git://anongit.freedesktop.org/drm/drm:
  drm/sun4i: Fix an ulong overflow in the dotclock driver
  drm: Get ref on CRTC commit object when waiting for flip_done

drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/sun4i/sun4i_dotclock.c
include/drm/drm_atomic.h

index 018fcdb353d254293456b613af5ed0e25ec07caa..281cf9cbb44c41981b7541408c97fda822fb0061 100644 (file)
@@ -174,6 +174,11 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
                state->crtcs[i].state = NULL;
                state->crtcs[i].old_state = NULL;
                state->crtcs[i].new_state = NULL;
+
+               if (state->crtcs[i].commit) {
+                       drm_crtc_commit_put(state->crtcs[i].commit);
+                       state->crtcs[i].commit = NULL;
+               }
        }
 
        for (i = 0; i < config->num_total_plane; i++) {
index 80be74df7ba66355163368f9f2b3eaeaf967a0d8..1bb4c318bdd4d36ae6e1b666176bd6134bf1e81f 100644 (file)
@@ -1408,15 +1408,16 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
 void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
                                          struct drm_atomic_state *old_state)
 {
-       struct drm_crtc_state *new_crtc_state;
        struct drm_crtc *crtc;
        int i;
 
-       for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
-               struct drm_crtc_commit *commit = new_crtc_state->commit;
+       for (i = 0; i < dev->mode_config.num_crtc; i++) {
+               struct drm_crtc_commit *commit = old_state->crtcs[i].commit;
                int ret;
 
-               if (!commit)
+               crtc = old_state->crtcs[i].ptr;
+
+               if (!crtc || !commit)
                        continue;
 
                ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
@@ -1934,6 +1935,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
                drm_crtc_commit_get(commit);
 
                commit->abort_completion = true;
+
+               state->crtcs[i].commit = commit;
+               drm_crtc_commit_get(commit);
        }
 
        for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
index e36004fbe45360deb9487fa80cdd564c33fa030e..2a15f2f9271ea26fe775dbed7276014cfe3b4fd7 100644 (file)
@@ -81,9 +81,19 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
        int i;
 
        for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) {
-               unsigned long ideal = rate * i;
+               u64 ideal = (u64)rate * i;
                unsigned long rounded;
 
+               /*
+                * ideal has overflowed the max value that can be stored in an
+                * unsigned long, and every clk operation we might do on a
+                * truncated u64 value will give us incorrect results.
+                * Let's just stop there since bigger dividers will result in
+                * the same overflow issue.
+                */
+               if (ideal > ULONG_MAX)
+                       goto out;
+
                rounded = clk_hw_round_rate(clk_hw_get_parent(hw),
                                            ideal);
 
index da9d95a1958096be400a3c4b9a4f5f1977d394e9..1e713154f00ee7776af628542302cb61f0a398e0 100644 (file)
@@ -153,6 +153,17 @@ struct __drm_planes_state {
 struct __drm_crtcs_state {
        struct drm_crtc *ptr;
        struct drm_crtc_state *state, *old_state, *new_state;
+
+       /**
+        * @commit:
+        *
+        * A reference to the CRTC commit object that is kept for use by
+        * drm_atomic_helper_wait_for_flip_done() after
+        * drm_atomic_helper_commit_hw_done() is called. This ensures that a
+        * concurrent commit won't free a commit object that is still in use.
+        */
+       struct drm_crtc_commit *commit;
+
        s32 __user *out_fence_ptr;
        u64 last_vblank_count;
 };