aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_atomic.c331
-rw-r--r--drivers/gpu/drm/drm_crtc.c4
-rw-r--r--drivers/gpu/drm/drm_ioctl.c1
-rw-r--r--include/drm/drm_crtc.h10
-rw-r--r--include/uapi/drm/drm.h1
-rw-r--r--include/uapi/drm/drm_mode.h23
6 files changed, 366 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 57cc68177f09..67f64bd1058f 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -56,6 +56,11 @@ drm_atomic_state_alloc(struct drm_device *dev)
56 if (!state) 56 if (!state)
57 return NULL; 57 return NULL;
58 58
59 /* TODO legacy paths should maybe do a better job about
60 * setting this appropriately?
61 */
62 state->allow_modeset = true;
63
59 state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); 64 state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
60 65
61 state->crtcs = kcalloc(dev->mode_config.num_crtc, 66 state->crtcs = kcalloc(dev->mode_config.num_crtc,
@@ -1003,6 +1008,22 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
1003 if (config->funcs->atomic_check) 1008 if (config->funcs->atomic_check)
1004 ret = config->funcs->atomic_check(state->dev, state); 1009 ret = config->funcs->atomic_check(state->dev, state);
1005 1010
1011 if (!state->allow_modeset) {
1012 for (i = 0; i < ncrtcs; i++) {
1013 struct drm_crtc *crtc = state->crtcs[i];
1014 struct drm_crtc_state *crtc_state = state->crtc_states[i];
1015
1016 if (!crtc)
1017 continue;
1018
1019 if (crtc_state->mode_changed) {
1020 DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n",
1021 crtc->base.id);
1022 return -EINVAL;
1023 }
1024 }
1025 }
1026
1006 return ret; 1027 return ret;
1007} 1028}
1008EXPORT_SYMBOL(drm_atomic_check_only); 1029EXPORT_SYMBOL(drm_atomic_check_only);
@@ -1068,3 +1089,313 @@ int drm_atomic_async_commit(struct drm_atomic_state *state)
1068 return config->funcs->atomic_commit(state->dev, state, true); 1089 return config->funcs->atomic_commit(state->dev, state, true);
1069} 1090}
1070EXPORT_SYMBOL(drm_atomic_async_commit); 1091EXPORT_SYMBOL(drm_atomic_async_commit);
1092
1093/*
1094 * The big monstor ioctl
1095 */
1096
1097static struct drm_pending_vblank_event *create_vblank_event(
1098 struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
1099{
1100 struct drm_pending_vblank_event *e = NULL;
1101 unsigned long flags;
1102
1103 spin_lock_irqsave(&dev->event_lock, flags);
1104 if (file_priv->event_space < sizeof e->event) {
1105 spin_unlock_irqrestore(&dev->event_lock, flags);
1106 goto out;
1107 }
1108 file_priv->event_space -= sizeof e->event;
1109 spin_unlock_irqrestore(&dev->event_lock, flags);
1110
1111 e = kzalloc(sizeof *e, GFP_KERNEL);
1112 if (e == NULL) {
1113 spin_lock_irqsave(&dev->event_lock, flags);
1114 file_priv->event_space += sizeof e->event;
1115 spin_unlock_irqrestore(&dev->event_lock, flags);
1116 goto out;
1117 }
1118
1119 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
1120 e->event.base.length = sizeof e->event;
1121 e->event.user_data = user_data;
1122 e->base.event = &e->event.base;
1123 e->base.file_priv = file_priv;
1124 e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
1125
1126out:
1127 return e;
1128}
1129
1130static void destroy_vblank_event(struct drm_device *dev,
1131 struct drm_file *file_priv, struct drm_pending_vblank_event *e)
1132{
1133 unsigned long flags;
1134
1135 spin_lock_irqsave(&dev->event_lock, flags);
1136 file_priv->event_space += sizeof e->event;
1137 spin_unlock_irqrestore(&dev->event_lock, flags);
1138 kfree(e);
1139}
1140
1141static int atomic_set_prop(struct drm_atomic_state *state,
1142 struct drm_mode_object *obj, struct drm_property *prop,
1143 uint64_t prop_value)
1144{
1145 struct drm_mode_object *ref;
1146 int ret;
1147
1148 if (!drm_property_change_valid_get(prop, prop_value, &ref))
1149 return -EINVAL;
1150
1151 switch (obj->type) {
1152 case DRM_MODE_OBJECT_CONNECTOR: {
1153 struct drm_connector *connector = obj_to_connector(obj);
1154 struct drm_connector_state *connector_state;
1155
1156 connector_state = drm_atomic_get_connector_state(state, connector);
1157 if (IS_ERR(connector_state)) {
1158 ret = PTR_ERR(connector_state);
1159 break;
1160 }
1161
1162 ret = drm_atomic_connector_set_property(connector,
1163 connector_state, prop, prop_value);
1164 break;
1165 }
1166 case DRM_MODE_OBJECT_CRTC: {
1167 struct drm_crtc *crtc = obj_to_crtc(obj);
1168 struct drm_crtc_state *crtc_state;
1169
1170 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1171 if (IS_ERR(crtc_state)) {
1172 ret = PTR_ERR(crtc_state);
1173 break;
1174 }
1175
1176 ret = drm_atomic_crtc_set_property(crtc,
1177 crtc_state, prop, prop_value);
1178 break;
1179 }
1180 case DRM_MODE_OBJECT_PLANE: {
1181 struct drm_plane *plane = obj_to_plane(obj);
1182 struct drm_plane_state *plane_state;
1183
1184 plane_state = drm_atomic_get_plane_state(state, plane);
1185 if (IS_ERR(plane_state)) {
1186 ret = PTR_ERR(plane_state);
1187 break;
1188 }
1189
1190 ret = drm_atomic_plane_set_property(plane,
1191 plane_state, prop, prop_value);
1192 break;
1193 }
1194 default:
1195 ret = -EINVAL;
1196 break;
1197 }
1198
1199 drm_property_change_valid_put(prop, ref);
1200 return ret;
1201}
1202
1203int drm_mode_atomic_ioctl(struct drm_device *dev,
1204 void *data, struct drm_file *file_priv)
1205{
1206 struct drm_mode_atomic *arg = data;
1207 uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
1208 uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
1209 uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
1210 uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
1211 unsigned int copied_objs, copied_props;
1212 struct drm_atomic_state *state;
1213 struct drm_modeset_acquire_ctx ctx;
1214 struct drm_plane *plane;
1215 unsigned plane_mask = 0;
1216 int ret = 0;
1217 unsigned int i, j;
1218
1219 /* disallow for drivers not supporting atomic: */
1220 if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
1221 return -EINVAL;
1222
1223 /* disallow for userspace that has not enabled atomic cap (even
1224 * though this may be a bit overkill, since legacy userspace
1225 * wouldn't know how to call this ioctl)
1226 */
1227 if (!file_priv->atomic)
1228 return -EINVAL;
1229
1230 if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS)
1231 return -EINVAL;
1232
1233 if (arg->reserved)
1234 return -EINVAL;
1235
1236 if ((arg->flags & DRM_MODE_PAGE