aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2014-12-18 16:01:56 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-01-05 07:55:29 -0500
commitd34f20d6e2f21bd3531b969dc40913181a8ae31a (patch)
tree05c0a22fb00068b2bc06bfedd078d97908da20b9
parentae16c597b61ae4613b13a0c3fac302e8d8827ac7 (diff)
drm: Atomic modeset ioctl
The atomic modeset ioctl can be used to push any number of new values for object properties. The driver can then check the full device configuration as single unit, and try to apply the changes atomically. The ioctl simply takes a list of object IDs and property IDs and their values. Originally based on a patch from Ville Syrjälä, although it has mutated (mutilated?) enough since then that you probably shouldn't blame it on him ;-) The atomic support is hidden behind the DRM_CLIENT_CAP_ATOMIC cap (to protect legacy userspace) and drm.atomic module param (for now). v2: Check for file_priv->atomic to make sure we only allow userspace in-the-know to use atomic. Signed-off-by: Rob Clark <robdclark@gmail.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-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_FLIP_ASYNC) &&
1237 !dev->mode_config.async_page_flip)
1238 return -EINVAL;
1239
1240 /* can't test and expect an event at the same time. */
1241 if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
1242 (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
1243 return -EINVAL;
1244
1245 drm_modeset_acquire_init(&ctx, 0);
1246
1247 state = drm_atomic_state_alloc(dev);
1248 if (!state)
1249 return -ENOMEM;
1250
1251 state->acquire_ctx = &ctx;
1252 state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
1253
1254retry:
1255 copied_objs = 0;
1256 copied_props = 0;
1257
1258 for (i = 0; i < arg->count_objs; i++) {
1259 uint32_t obj_id, count_props;
1260 struct drm_mode_object *obj;
1261
1262 if (get_user(obj_id, objs_ptr + copied_objs)) {
1263 ret = -EFAULT;
1264 goto fail;
1265 }
1266
1267 obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
1268 if (!obj || !obj->properties) {
1269 ret = -ENOENT;
1270 goto fail;
1271 }
1272
1273 if (obj->type == DRM_MODE_OBJECT_PLANE) {
1274 plane = obj_to_plane(obj);
1275 plane_mask |= (1 << drm_plane_index(plane));
1276 plane->old_fb = plane->fb;
1277 }
1278
1279 if (get_user(count_props, count_props_ptr + copied_objs)) {
1280 ret = -EFAULT;
1281 goto fail;
1282 }
1283
1284 copied_objs++;
1285
1286 for (j = 0; j < count_props; j++) {
1287 uint32_t prop_id;
1288 uint64_t prop_value;
1289 struct drm_property *prop;
1290
1291 if (get_user(prop_id, props_ptr + copied_props)) {
1292 ret = -EFAULT;
1293 goto fail;
1294 }
1295
1296 prop = drm_property_find(dev, prop_id);
1297 if (!prop) {
1298 ret = -ENOENT;
1299 goto fail;
1300 }
1301
1302 if (get_user(prop_value, prop_values_ptr + copied_props)) {
1303 ret = -EFAULT;
1304 goto fail;
1305 }
1306
1307 ret = atomic_set_prop(state, obj, prop, prop_value);
1308 if (ret)
1309 goto fail;
1310
1311 copied_props++;
1312 }
1313 }
1314
1315 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1316 int ncrtcs = dev->mode_config.num_crtc;
1317
1318 for (i = 0; i < ncrtcs; i++) {
1319 struct drm_crtc_state *crtc_state = state->crtc_states[i];
1320 struct drm_pending_vblank_event *e;
1321
1322 if (!crtc_state)
1323 continue;
1324
1325 e = create_vblank_event(dev, file_priv, arg->user_data);
1326 if (!e) {
1327 ret = -ENOMEM;
1328 goto fail;
1329 }
1330
1331 crtc_state->event = e;
1332 }
1333 }
1334
1335 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
1336 ret = drm_atomic_check_only(state);
1337 /* _check_only() does not free state, unlike _commit() */
1338 drm_atomic_state_free(state);
1339 } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
1340 ret = drm_atomic_async_commit(state);
1341 } else {
1342 ret = drm_atomic_commit(state);
1343 }
1344
1345 /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
1346 * locks (ie. while it is still safe to deref plane->state). We
1347 * need to do this here because the driver entry points cannot
1348 * distinguish between legacy and atomic ioctls.
1349 */
1350 drm_for_each_plane_mask(plane, dev, plane_mask) {
1351 if (ret == 0) {
1352 struct drm_framebuffer *new_fb = plane->state->fb;
1353 if (new_fb)
1354 drm_framebuffer_reference(new_fb);
1355 plane->fb = new_fb;
1356 plane->crtc = plane->state->crtc;
1357 } else {
1358 plane->old_fb = NULL;
1359 }
1360 if (plane->old_fb) {
1361 drm_framebuffer_unreference(plane->old_fb);
1362 plane->old_fb = NULL;
1363 }
1364 }
1365
1366 drm_modeset_drop_locks(&ctx);
1367 drm_modeset_acquire_fini(&ctx);
1368
1369 return ret;
1370
1371fail:
1372 if (ret == -EDEADLK)
1373 goto backoff;
1374
1375 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1376 int ncrtcs = dev->mode_config.num_crtc;
1377
1378 for (i = 0; i < ncrtcs; i++) {
1379 struct drm_crtc_state *crtc_state = state->crtc_states[i];
1380
1381 if (!crtc_state)
1382 continue;
1383
1384 destroy_vblank_event(dev, file_priv, crtc_state->event);
1385 crtc_state->event = NULL;
1386 }
1387 }
1388
1389 drm_atomic_state_free(state);
1390
1391 drm_modeset_drop_locks(&ctx);
1392 drm_modeset_acquire_fini(&ctx);
1393
1394 return ret;
1395
1396backoff:
1397 drm_atomic_state_clear(state);
1398 drm_modeset_backoff(&ctx);
1399
1400 goto retry;
1401}
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3cb1fa09ac9e..20596423d52d 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -4303,7 +4303,7 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
4303 * object to which the property is attached has a chance to take it's own 4303 * object to which the property is attached has a chance to take it's own
4304 * reference). 4304 * reference).
4305 */ 4305 */
4306static bool drm_property_change_valid_get(struct drm_property *property, 4306bool drm_property_change_valid_get(struct drm_property *property,
4307 uint64_t value, struct drm_mode_object **ref) 4307 uint64_t value, struct drm_mode_object **ref)
4308{ 4308{
4309 int i; 4309 int i;
@@ -4365,7 +4365,7 @@ static bool drm_property_change_valid_get(struct drm_property *property,
4365 return false; 4365 return false;
4366} 4366}
4367 4367
4368static void drm_property_change_valid_put(struct drm_property *property, 4368void drm_property_change_valid_put(struct drm_property *property,
4369 struct drm_mode_object *ref) 4369 struct drm_mode_object *ref)
4370{ 4370{
4371 if (!ref) 4371 if (!ref)
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index adc822312f6c..a28c0abd1a38 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -630,6 +630,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
630 DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), 630 DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
631 DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), 631 DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
632 DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), 632 DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
633 DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
633}; 634};
634 635
635#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) 636#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index fc4767fa723b..1dcfb685d15f 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -902,7 +902,7 @@ struct drm_bridge {
902/** 902/**
903 * struct struct drm_atomic_state - the global state object for atomic updates 903 * struct struct drm_atomic_state - the global state object for atomic updates
904 * @dev: parent DRM device 904 * @dev: parent DRM device
905 * @flags: state flags like async update 905 * @allow_modeset: allow full modeset
906 * @planes: pointer to array of plane pointers 906 * @planes: pointer to array of plane pointers
907 * @plane_states: pointer to array of plane states pointers 907 * @plane_states: pointer to array of plane states pointers
908 * @crtcs: pointer to array of CRTC pointers 908 * @crtcs: pointer to array of CRTC pointers
@@ -914,7 +914,7 @@ struct drm_bridge {
914 */ 914 */
915struct drm_atomic_state { 915struct drm_atomic_state {
916 struct drm_device *dev; 916 struct drm_device *dev;
917 uint32_t flags; 917 bool allow_modeset : 1;
918 struct drm_plane **planes; 918 struct drm_plane **planes;
919 struct drm_plane_state **plane_states; 919 struct drm_plane_state **plane_states;
920 struct drm_crtc **crtcs; 920 struct drm_crtc **crtcs;
@@ -1346,6 +1346,10 @@ extern int drm_mode_create_scaling_mode_property(struct drm_device *dev);
1346extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev); 1346extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
1347extern int drm_mode_create_dirty_info_property(struct drm_device *dev); 1347extern int drm_mode_create_dirty_info_property(struct drm_device *dev);
1348extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev); 1348extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
1349extern bool drm_property_change_valid_get(struct drm_property *property,
1350 uint64_t value, struct drm_mode_object **ref);
1351extern void drm_property_change_valid_put(struct drm_property *property,
1352 struct drm_mode_object *ref);
1349 1353
1350extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, 1354extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
1351 struct drm_encoder *encoder); 1355 struct drm_encoder *encoder);
@@ -1437,6 +1441,8 @@ extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
1437extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 1441extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
1438 struct drm_property *property, 1442 struct drm_property *property,
1439 uint64_t value); 1443 uint64_t value);
1444extern int drm_mode_atomic_ioctl(struct drm_device *dev,
1445 void *data, struct drm_file *file_priv);
1440 1446
1441extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 1447extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
1442 int *bpp); 1448 int *bpp);
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index f7b2baf7ecb2..01b2d6d0e355 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -784,6 +784,7 @@ struct drm_prime_handle {
784#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) 784#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
785#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) 785#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
786#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2) 786#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2)
787#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic)
787 788
788/** 789/**
789 * Device specific ioctls should only be in their respective headers 790 * Device specific ioctls should only be in their respective headers
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index b8f9c0f2e7fe..ca788e01dab2 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -526,4 +526,27 @@ struct drm_mode_destroy_dumb {
526 uint32_t handle; 526 uint32_t handle;
527}; 527};
528 528
529/* page-flip flags are valid, plus: */
530#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100
531#define DRM_MODE_ATOMIC_NONBLOCK 0x0200
532#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400
533
534#define DRM_MODE_ATOMIC_FLAGS (\
535 DRM_MODE_PAGE_FLIP_EVENT |\
536 DRM_MODE_PAGE_FLIP_ASYNC |\
537 DRM_MODE_ATOMIC_TEST_ONLY |\
538 DRM_MODE_ATOMIC_NONBLOCK |\
539 DRM_MODE_ATOMIC_ALLOW_MODESET)
540
541struct drm_mode_atomic {
542 __u32 flags;
543 __u32 count_objs;
544 __u64 objs_ptr;
545 __u64 count_props_ptr;
546 __u64 props_ptr;
547 __u64 prop_values_ptr;
548 __u64 reserved;
549 __u64 user_data;
550};
551
529#endif 552#endif