1 /* 2 * Copyright (C) 2014 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "msm_drv.h" 19 #include "msm_kms.h" 20 #include "msm_gem.h" 21 22 struct msm_commit { 23 struct drm_atomic_state *state; 24 uint32_t fence; 25 struct msm_fence_cb fence_cb; 26 }; 27 28 static void fence_cb(struct msm_fence_cb *cb); 29 30 static struct msm_commit *new_commit(struct drm_atomic_state *state) 31 { 32 struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); 33 34 if (!c) 35 return NULL; 36 37 c->state = state; 38 /* TODO we might need a way to indicate to run the cb on a 39 * different wq so wait_for_vblanks() doesn't block retiring 40 * bo's.. 41 */ 42 INIT_FENCE_CB(&c->fence_cb, fence_cb); 43 44 return c; 45 } 46 47 /* The (potentially) asynchronous part of the commit. At this point 48 * nothing can fail short of armageddon. 49 */ 50 static void complete_commit(struct msm_commit *c) 51 { 52 struct drm_atomic_state *state = c->state; 53 struct drm_device *dev = state->dev; 54 55 drm_atomic_helper_commit_pre_planes(dev, state); 56 57 drm_atomic_helper_commit_planes(dev, state); 58 59 drm_atomic_helper_commit_post_planes(dev, state); 60 61 drm_atomic_helper_wait_for_vblanks(dev, state); 62 63 drm_atomic_helper_cleanup_planes(dev, state); 64 65 drm_atomic_state_free(state); 66 67 kfree(c); 68 } 69 70 static void fence_cb(struct msm_fence_cb *cb) 71 { 72 struct msm_commit *c = 73 container_of(cb, struct msm_commit, fence_cb); 74 complete_commit(c); 75 } 76 77 static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) 78 { 79 struct drm_gem_object *obj = msm_framebuffer_bo(fb, 0); 80 c->fence = max(c->fence, msm_gem_fence(to_msm_bo(obj), MSM_PREP_READ)); 81 } 82 83 84 /** 85 * drm_atomic_helper_commit - commit validated state object 86 * @dev: DRM device 87 * @state: the driver state object 88 * @async: asynchronous commit 89 * 90 * This function commits a with drm_atomic_helper_check() pre-validated state 91 * object. This can still fail when e.g. the framebuffer reservation fails. For 92 * now this doesn't implement asynchronous commits. 93 * 94 * RETURNS 95 * Zero for success or -errno. 96 */ 97 int msm_atomic_commit(struct drm_device *dev, 98 struct drm_atomic_state *state, bool async) 99 { 100 struct msm_commit *c; 101 int nplanes = dev->mode_config.num_total_plane; 102 int i, ret; 103 104 ret = drm_atomic_helper_prepare_planes(dev, state); 105 if (ret) 106 return ret; 107 108 c = new_commit(state); 109 110 /* 111 * Figure out what fence to wait for: 112 */ 113 for (i = 0; i < nplanes; i++) { 114 struct drm_plane *plane = state->planes[i]; 115 struct drm_plane_state *new_state = state->plane_states[i]; 116 117 if (!plane) 118 continue; 119 120 if ((plane->state->fb != new_state->fb) && new_state->fb) 121 add_fb(c, new_state->fb); 122 } 123 124 /* 125 * This is the point of no return - everything below never fails except 126 * when the hw goes bonghits. Which means we can commit the new state on 127 * the software side now. 128 */ 129 130 drm_atomic_helper_swap_state(dev, state); 131 132 /* 133 * Everything below can be run asynchronously without the need to grab 134 * any modeset locks at all under one conditions: It must be guaranteed 135 * that the asynchronous work has either been cancelled (if the driver 136 * supports it, which at least requires that the framebuffers get 137 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed 138 * before the new state gets committed on the software side with 139 * drm_atomic_helper_swap_state(). 140 * 141 * This scheme allows new atomic state updates to be prepared and 142 * checked in parallel to the asynchronous completion of the previous 143 * update. Which is important since compositors need to figure out the 144 * composition of the next frame right after having submitted the 145 * current layout. 146 */ 147 148 if (async) { 149 msm_queue_fence_cb(dev, &c->fence_cb, c->fence); 150 return 0; 151 } 152 153 ret = msm_wait_fence_interruptable(dev, c->fence, NULL); 154 if (ret) { 155 WARN_ON(ret); // TODO unswap state back? or?? 156 kfree(c); 157 return ret; 158 } 159 160 complete_commit(c); 161 162 return 0; 163 } 164