diff options
| -rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 331 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 1 | ||||
| -rw-r--r-- | include/drm/drm_crtc.h | 10 | ||||
| -rw-r--r-- | include/uapi/drm/drm.h | 1 | ||||
| -rw-r--r-- | include/uapi/drm/drm_mode.h | 23 |
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 | } |
| 1008 | EXPORT_SYMBOL(drm_atomic_check_only); | 1029 | EXPORT_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 | } |
| 1070 | EXPORT_SYMBOL(drm_atomic_async_commit); | 1091 | EXPORT_SYMBOL(drm_atomic_async_commit); |
| 1092 | |||
| 1093 | /* | ||
| 1094 | * The big monstor ioctl | ||
| 1095 | */ | ||
| 1096 | |||
| 1097 | static 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 | |||
| 1126 | out: | ||
| 1127 | return e; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | static 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 | |||
| 1141 | static 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 | |||
| 1203 | int 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 | ||
