v2: individually allocate chain array, since chain node is free independently. v3: all existing points must be already signaled before cpu perform signal operation, so add check condition for that. v4: remove v3 change and add checking to prevent out-of-order v5: unify binary and timeline
Unified · Split
| @@ -190,6 +190,8 @@ int drm_syncobj_reset_ioctl(struct drm_device *dev, void *data, · 189 unmodified lines | |||
| 190 | struct drm_file *file_private); | 190 | struct drm_file *file_private); |
| 191 | int drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, | 191 | int drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, |
| 192 | struct drm_file *file_private); | 192 | struct drm_file *file_private); |
| 193 | int drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, | ||
| 194 | struct drm_file *file_private); | ||
| 193 | int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, | 195 | int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, |
| 194 | struct drm_file *file_private); | 196 | struct drm_file *file_private); |
| 195 | 197 | ||
| @@ -696,6 +696,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = { · 695 unmodified lines | |||
| 696 | DRM_UNLOCKED|DRM_RENDER_ALLOW), | 696 | DRM_UNLOCKED|DRM_RENDER_ALLOW), |
| 697 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl, | 697 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl, |
| 698 | DRM_UNLOCKED|DRM_RENDER_ALLOW), | 698 | DRM_UNLOCKED|DRM_RENDER_ALLOW), |
| 699 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, drm_syncobj_timeline_signal_ioctl, | ||
| 700 | DRM_UNLOCKED|DRM_RENDER_ALLOW), | ||
| 699 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_QUERY, drm_syncobj_query_ioctl, | 701 | DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_QUERY, drm_syncobj_query_ioctl, |
| 700 | DRM_UNLOCKED|DRM_RENDER_ALLOW), | 702 | DRM_UNLOCKED|DRM_RENDER_ALLOW), |
| 701 | DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, DRM_UNLOCKED), | 703 | DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, DRM_UNLOCKED), |
| @@ -1184,6 +1184,79 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, · 1183 unmodified lines | |||
| 1184 | return ret; | 1184 | return ret; |
| 1185 | } | 1185 | } |
| 1186 | 1186 | ||
| 1187 | int | ||
| 1188 | drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, | ||
| 1189 | struct drm_file *file_private) | ||
| 1190 | { | ||
| 1191 | struct drm_syncobj_timeline_array *args = data; | ||
| 1192 | struct drm_syncobj **syncobjs; | ||
| 1193 | struct dma_fence_chain **chains; | ||
| 1194 | uint64_t *points; | ||
| 1195 | uint32_t i, j; | ||
| 1196 | int ret; | ||
| 1197 | |||
| 1198 | if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) | ||
| 1199 | return -EOPNOTSUPP; | ||
| 1200 | |||
| 1201 | if (args->pad != 0) | ||
| 1202 | return -EINVAL; | ||
| 1203 | |||
| 1204 | if (args->count_handles == 0) | ||
| 1205 | return -EINVAL; | ||
| 1206 | |||
| 1207 | ret = drm_syncobj_array_find(file_private, | ||
| 1208 | u64_to_user_ptr(args->handles), | ||
| 1209 | args->count_handles, | ||
| 1210 | &syncobjs); | ||
| 1211 | if (ret < 0) | ||
| 1212 | return ret; | ||
| 1213 | |||
| 1214 | points = kmalloc_array(args->count_handles, sizeof(*points), | ||
| 1215 | GFP_KERNEL); | ||
| 1216 | if (!points) { | ||
| 1217 | ret = -ENOMEM; | ||
| 1218 | goto out; | ||
| 1219 | } | ||
| 1220 | if (!u64_to_user_ptr(args->points)) { | ||
| 1221 | memset(points, 0, args->count_handles * sizeof(uint64_t)); | ||
| 1222 | } else if (copy_from_user(points, u64_to_user_ptr(args->points), | ||
| 1223 | sizeof(uint64_t) * args->count_handles)) { | ||
| 1224 | ret = -EFAULT; | ||
| 1225 | goto err_points; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL); | ||
| 1229 | if (!chains) { | ||
| 1230 | ret = -ENOMEM; | ||
| 1231 | goto err_points; | ||
| 1232 | } | ||
| 1233 | for (i = 0; i < args->count_handles; i++) { | ||
| 1234 | chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); | ||
| 1235 | if (!chains[i]) { | ||
| 1236 | for (j = 0; j < i; j++) | ||
| 1237 | kfree(chains[j]); | ||
| 1238 | ret = -ENOMEM; | ||
| 1239 | goto err_chains; | ||
| 1240 | } | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | for (i = 0; i < args->count_handles; i++) { | ||
| 1244 | struct dma_fence *fence = dma_fence_get_stub(); | ||
| 1245 | |||
| 1246 | drm_syncobj_add_point(syncobjs[i], chains[i], | ||
| 1247 | fence, points[i]); | ||
| 1248 | dma_fence_put(fence); | ||
| 1249 | } | ||
| 1250 | err_chains: | ||
| 1251 | kfree(chains); | ||
| 1252 | err_points: | ||
| 1253 | kfree(points); | ||
| 1254 | out: | ||
| 1255 | drm_syncobj_array_free(syncobjs, args->count_handles); | ||
| 1256 | |||
| 1257 | return ret; | ||
| 1258 | } | ||
| 1259 | |||
| 1187 | int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, | 1260 | int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, |
| 1188 | struct drm_file *file_private) | 1261 | struct drm_file *file_private) |
| 1189 | { | 1262 | { |
| @@ -943,6 +943,7 @@ extern "C" { · 942 unmodified lines | |||
| 943 | #define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT DRM_IOWR(0xCA, struct drm_syncobj_timeline_wait) | 943 | #define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT DRM_IOWR(0xCA, struct drm_syncobj_timeline_wait) |
| 944 | #define DRM_IOCTL_SYNCOBJ_QUERY DRM_IOWR(0xCB, struct drm_syncobj_timeline_array) | 944 | #define DRM_IOCTL_SYNCOBJ_QUERY DRM_IOWR(0xCB, struct drm_syncobj_timeline_array) |
| 945 | #define DRM_IOCTL_SYNCOBJ_TRANSFER DRM_IOWR(0xCC, struct drm_syncobj_transfer) | 945 | #define DRM_IOCTL_SYNCOBJ_TRANSFER DRM_IOWR(0xCC, struct drm_syncobj_transfer) |
| 946 | #define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL DRM_IOWR(0xCD, struct drm_syncobj_timeline_array) | ||
| 946 | 947 | ||
| 947 | /** | 948 | /** |
| 948 | * Device specific ioctls should only be in their respective headers | 949 | * Device specific ioctls should only be in their respective headers |