diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 345 |
1 files changed, 230 insertions, 115 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2892d746a1e9..7e4acad3f6f9 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <drm/drm_edid.h> | 38 | #include <drm/drm_edid.h> |
39 | #include <drm/drm_fourcc.h> | 39 | #include <drm/drm_fourcc.h> |
40 | #include <drm/drm_modeset_lock.h> | 40 | #include <drm/drm_modeset_lock.h> |
41 | #include <drm/drm_atomic.h> | ||
41 | 42 | ||
42 | #include "drm_crtc_internal.h" | 43 | #include "drm_crtc_internal.h" |
43 | #include "drm_internal.h" | 44 | #include "drm_internal.h" |
@@ -830,6 +831,7 @@ int drm_connector_init(struct drm_device *dev, | |||
830 | const struct drm_connector_funcs *funcs, | 831 | const struct drm_connector_funcs *funcs, |
831 | int connector_type) | 832 | int connector_type) |
832 | { | 833 | { |
834 | struct drm_mode_config *config = &dev->mode_config; | ||
833 | int ret; | 835 | int ret; |
834 | struct ida *connector_ida = | 836 | struct ida *connector_ida = |
835 | &drm_connector_enum_list[connector_type].ida; | 837 | &drm_connector_enum_list[connector_type].ida; |
@@ -868,16 +870,20 @@ int drm_connector_init(struct drm_device *dev, | |||
868 | 870 | ||
869 | /* We should add connectors at the end to avoid upsetting the connector | 871 | /* We should add connectors at the end to avoid upsetting the connector |
870 | * index too much. */ | 872 | * index too much. */ |
871 | list_add_tail(&connector->head, &dev->mode_config.connector_list); | 873 | list_add_tail(&connector->head, &config->connector_list); |
872 | dev->mode_config.num_connector++; | 874 | config->num_connector++; |
873 | 875 | ||
874 | if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) | 876 | if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) |
875 | drm_object_attach_property(&connector->base, | 877 | drm_object_attach_property(&connector->base, |
876 | dev->mode_config.edid_property, | 878 | config->edid_property, |
877 | 0); | 879 | 0); |
878 | 880 | ||
879 | drm_object_attach_property(&connector->base, | 881 | drm_object_attach_property(&connector->base, |
880 | dev->mode_config.dpms_property, 0); | 882 | config->dpms_property, 0); |
883 | |||
884 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
885 | drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); | ||
886 | } | ||
881 | 887 | ||
882 | connector->debugfs_entry = NULL; | 888 | connector->debugfs_entry = NULL; |
883 | 889 | ||
@@ -1168,6 +1174,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
1168 | const uint32_t *formats, uint32_t format_count, | 1174 | const uint32_t *formats, uint32_t format_count, |
1169 | enum drm_plane_type type) | 1175 | enum drm_plane_type type) |
1170 | { | 1176 | { |
1177 | struct drm_mode_config *config = &dev->mode_config; | ||
1171 | int ret; | 1178 | int ret; |
1172 | 1179 | ||
1173 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | 1180 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); |
@@ -1192,15 +1199,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
1192 | plane->possible_crtcs = possible_crtcs; | 1199 | plane->possible_crtcs = possible_crtcs; |
1193 | plane->type = type; | 1200 | plane->type = type; |
1194 | 1201 | ||
1195 | list_add_tail(&plane->head, &dev->mode_config.plane_list); | 1202 | list_add_tail(&plane->head, &config->plane_list); |
1196 | dev->mode_config.num_total_plane++; | 1203 | config->num_total_plane++; |
1197 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | 1204 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) |
1198 | dev->mode_config.num_overlay_plane++; | 1205 | config->num_overlay_plane++; |
1199 | 1206 | ||
1200 | drm_object_attach_property(&plane->base, | 1207 | drm_object_attach_property(&plane->base, |
1201 | dev->mode_config.plane_type_property, | 1208 | config->plane_type_property, |
1202 | plane->type); | 1209 | plane->type); |
1203 | 1210 | ||
1211 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { | ||
1212 | drm_object_attach_property(&plane->base, config->prop_fb_id, 0); | ||
1213 | drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); | ||
1214 | drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); | ||
1215 | drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); | ||
1216 | drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); | ||
1217 | drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); | ||
1218 | drm_object_attach_property(&plane->base, config->prop_src_x, 0); | ||
1219 | drm_object_attach_property(&plane->base, config->prop_src_y, 0); | ||
1220 | drm_object_attach_property(&plane->base, config->prop_src_w, 0); | ||
1221 | drm_object_attach_property(&plane->base, config->prop_src_h, 0); | ||
1222 | } | ||
1223 | |||
1204 | return 0; | 1224 | return 0; |
1205 | } | 1225 | } |
1206 | EXPORT_SYMBOL(drm_universal_plane_init); | 1226 | EXPORT_SYMBOL(drm_universal_plane_init); |
@@ -1322,50 +1342,109 @@ void drm_plane_force_disable(struct drm_plane *plane) | |||
1322 | } | 1342 | } |
1323 | EXPORT_SYMBOL(drm_plane_force_disable); | 1343 | EXPORT_SYMBOL(drm_plane_force_disable); |
1324 | 1344 | ||
1325 | static int drm_mode_create_standard_connector_properties(struct drm_device *dev) | 1345 | static int drm_mode_create_standard_properties(struct drm_device *dev) |
1326 | { | 1346 | { |
1327 | struct drm_property *edid; | 1347 | struct drm_property *prop; |
1328 | struct drm_property *dpms; | ||
1329 | struct drm_property *dev_path; | ||
1330 | 1348 | ||
1331 | /* | 1349 | /* |
1332 | * Standard properties (apply to all connectors) | 1350 | * Standard properties (apply to all connectors) |
1333 | */ | 1351 | */ |
1334 | edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | | 1352 | prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | |
1335 | DRM_MODE_PROP_IMMUTABLE, | 1353 | DRM_MODE_PROP_IMMUTABLE, |
1336 | "EDID", 0); | 1354 | "EDID", 0); |
1337 | dev->mode_config.edid_property = edid; | 1355 | if (!prop) |
1356 | return -ENOMEM; | ||
1357 | dev->mode_config.edid_property = prop; | ||
1338 | 1358 | ||
1339 | dpms = drm_property_create_enum(dev, 0, | 1359 | prop = drm_property_create_enum(dev, 0, |
1340 | "DPMS", drm_dpms_enum_list, | 1360 | "DPMS", drm_dpms_enum_list, |
1341 | ARRAY_SIZE(drm_dpms_enum_list)); | 1361 | ARRAY_SIZE(drm_dpms_enum_list)); |
1342 | dev->mode_config.dpms_property = dpms; | 1362 | if (!prop) |
1343 | 1363 | return -ENOMEM; | |
1344 | dev_path = drm_property_create(dev, | 1364 | dev->mode_config.dpms_property = prop; |
1345 | DRM_MODE_PROP_BLOB | | ||
1346 | DRM_MODE_PROP_IMMUTABLE, | ||
1347 | "PATH", 0); | ||
1348 | dev->mode_config.path_property = dev_path; | ||
1349 | |||
1350 | dev->mode_config.tile_property = drm_property_create(dev, | ||
1351 | DRM_MODE_PROP_BLOB | | ||
1352 | DRM_MODE_PROP_IMMUTABLE, | ||
1353 | "TILE", 0); | ||
1354 | 1365 | ||
1355 | return 0; | 1366 | prop = drm_property_create(dev, |
1356 | } | 1367 | DRM_MODE_PROP_BLOB | |
1368 | DRM_MODE_PROP_IMMUTABLE, | ||
1369 | "PATH", 0); | ||
1370 | if (!prop) | ||
1371 | return -ENOMEM; | ||
1372 | dev->mode_config.path_property = prop; | ||
1357 | 1373 | ||
1358 | static int drm_mode_create_standard_plane_properties(struct drm_device *dev) | 1374 | prop = drm_property_create(dev, |
1359 | { | 1375 | DRM_MODE_PROP_BLOB | |
1360 | struct drm_property *type; | 1376 | DRM_MODE_PROP_IMMUTABLE, |
1377 | "TILE", 0); | ||
1378 | if (!prop) | ||
1379 | return -ENOMEM; | ||
1380 | dev->mode_config.tile_property = prop; | ||
1361 | 1381 | ||
1362 | /* | 1382 | prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, |
1363 | * Standard properties (apply to all planes) | ||
1364 | */ | ||
1365 | type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, | ||
1366 | "type", drm_plane_type_enum_list, | 1383 | "type", drm_plane_type_enum_list, |
1367 | ARRAY_SIZE(drm_plane_type_enum_list)); | 1384 | ARRAY_SIZE(drm_plane_type_enum_list)); |
1368 | dev->mode_config.plane_type_property = type; | 1385 | if (!prop) |
1386 | return -ENOMEM; | ||
1387 | dev->mode_config.plane_type_property = prop; | ||
1388 | |||
1389 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1390 | "SRC_X", 0, UINT_MAX); | ||
1391 | if (!prop) | ||
1392 | return -ENOMEM; | ||
1393 | dev->mode_config.prop_src_x = prop; | ||
1394 | |||
1395 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1396 | "SRC_Y", 0, UINT_MAX); | ||
1397 | if (!prop) | ||
1398 | return -ENOMEM; | ||
1399 | dev->mode_config.prop_src_y = prop; | ||
1400 | |||
1401 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1402 | "SRC_W", 0, UINT_MAX); | ||
1403 | if (!prop) | ||
1404 | return -ENOMEM; | ||
1405 | dev->mode_config.prop_src_w = prop; | ||
1406 | |||
1407 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1408 | "SRC_H", 0, UINT_MAX); | ||
1409 | if (!prop) | ||
1410 | return -ENOMEM; | ||
1411 | dev->mode_config.prop_src_h = prop; | ||
1412 | |||
1413 | prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1414 | "CRTC_X", INT_MIN, INT_MAX); | ||
1415 | if (!prop) | ||
1416 | return -ENOMEM; | ||
1417 | dev->mode_config.prop_crtc_x = prop; | ||
1418 | |||
1419 | prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1420 | "CRTC_Y", INT_MIN, INT_MAX); | ||
1421 | if (!prop) | ||
1422 | return -ENOMEM; | ||
1423 | dev->mode_config.prop_crtc_y = prop; | ||
1424 | |||
1425 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1426 | "CRTC_W", 0, INT_MAX); | ||
1427 | if (!prop) | ||
1428 | return -ENOMEM; | ||
1429 | dev->mode_config.prop_crtc_w = prop; | ||
1430 | |||
1431 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
1432 | "CRTC_H", 0, INT_MAX); | ||
1433 | if (!prop) | ||
1434 | return -ENOMEM; | ||
1435 | dev->mode_config.prop_crtc_h = prop; | ||
1436 | |||
1437 | prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, | ||
1438 | "FB_ID", DRM_MODE_OBJECT_FB); | ||
1439 | if (!prop) | ||
1440 | return -ENOMEM; | ||
1441 | dev->mode_config.prop_fb_id = prop; | ||
1442 | |||
1443 | prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, | ||
1444 | "CRTC_ID", DRM_MODE_OBJECT_CRTC); | ||
1445 | if (!prop) | ||
1446 | return -ENOMEM; | ||
1447 | dev->mode_config.prop_crtc_id = prop; | ||
1369 | 1448 | ||
1370 | return 0; | 1449 | return 0; |
1371 | } | 1450 | } |
@@ -1991,6 +2070,44 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne | |||
1991 | return connector->encoder; | 2070 | return connector->encoder; |
1992 | } | 2071 | } |
1993 | 2072 | ||
2073 | /* helper for getconnector and getproperties ioctls */ | ||
2074 | static int get_properties(struct drm_mode_object *obj, bool atomic, | ||
2075 | uint32_t __user *prop_ptr, uint64_t __user *prop_values, | ||
2076 | uint32_t *arg_count_props) | ||
2077 | { | ||
2078 | int props_count; | ||
2079 | int i, ret, copied; | ||
2080 | |||
2081 | props_count = obj->properties->count; | ||
2082 | if (!atomic) | ||
2083 | props_count -= obj->properties->atomic_count; | ||
2084 | |||
2085 | if ((*arg_count_props >= props_count) && props_count) { | ||
2086 | for (i = 0, copied = 0; copied < props_count; i++) { | ||
2087 | struct drm_property *prop = obj->properties->properties[i]; | ||
2088 | uint64_t val; | ||
2089 | |||
2090 | if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) | ||
2091 | continue; | ||
2092 | |||
2093 | ret = drm_object_property_get_value(obj, prop, &val); | ||
2094 | if (ret) | ||
2095 | return ret; | ||
2096 | |||
2097 | if (put_user(prop->base.id, prop_ptr + copied)) | ||
2098 | return -EFAULT; | ||
2099 | |||
2100 | if (put_user(val, prop_values + copied)) | ||
2101 | return -EFAULT; | ||
2102 | |||
2103 | copied++; | ||
2104 | } | ||
2105 | } | ||
2106 | *arg_count_props = props_count; | ||
2107 | |||
2108 | return 0; | ||
2109 | } | ||
2110 | |||
1994 | /** | 2111 | /** |
1995 | * drm_mode_getconnector - get connector configuration | 2112 | * drm_mode_getconnector - get connector configuration |
1996 | * @dev: drm device for the ioctl | 2113 | * @dev: drm device for the ioctl |
@@ -2012,15 +2129,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2012 | struct drm_encoder *encoder; | 2129 | struct drm_encoder *encoder; |
2013 | struct drm_display_mode *mode; | 2130 | struct drm_display_mode *mode; |
2014 | int mode_count = 0; | 2131 | int mode_count = 0; |
2015 | int props_count = 0; | ||
2016 | int encoders_count = 0; | 2132 | int encoders_count = 0; |
2017 | int ret = 0; | 2133 | int ret = 0; |
2018 | int copied = 0; | 2134 | int copied = 0; |
2019 | int i; | 2135 | int i; |
2020 | struct drm_mode_modeinfo u_mode; | 2136 | struct drm_mode_modeinfo u_mode; |
2021 | struct drm_mode_modeinfo __user *mode_ptr; | 2137 | struct drm_mode_modeinfo __user *mode_ptr; |
2022 | uint32_t __user *prop_ptr; | ||
2023 | uint64_t __user *prop_values; | ||
2024 | uint32_t __user *encoder_ptr; | 2138 | uint32_t __user *encoder_ptr; |
2025 | 2139 | ||
2026 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2140 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
@@ -2031,6 +2145,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2031 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); | 2145 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); |
2032 | 2146 | ||
2033 | mutex_lock(&dev->mode_config.mutex); | 2147 | mutex_lock(&dev->mode_config.mutex); |
2148 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
2034 | 2149 | ||
2035 | connector = drm_connector_find(dev, out_resp->connector_id); | 2150 | connector = drm_connector_find(dev, out_resp->connector_id); |
2036 | if (!connector) { | 2151 | if (!connector) { |
@@ -2038,8 +2153,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2038 | goto out; | 2153 | goto out; |
2039 | } | 2154 | } |
2040 | 2155 | ||
2041 | props_count = connector->properties.count; | ||
2042 | |||
2043 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) | 2156 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) |
2044 | if (connector->encoder_ids[i] != 0) | 2157 | if (connector->encoder_ids[i] != 0) |
2045 | encoders_count++; | 2158 | encoders_count++; |
@@ -2062,14 +2175,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2062 | out_resp->mm_height = connector->display_info.height_mm; | 2175 | out_resp->mm_height = connector->display_info.height_mm; |
2063 | out_resp->subpixel = connector->display_info.subpixel_order; | 2176 | out_resp->subpixel = connector->display_info.subpixel_order; |
2064 | out_resp->connection = connector->status; | 2177 | out_resp->connection = connector->status; |
2065 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | ||
2066 | |||
2067 | encoder = drm_connector_get_encoder(connector); | 2178 | encoder = drm_connector_get_encoder(connector); |
2068 | if (encoder) | 2179 | if (encoder) |
2069 | out_resp->encoder_id = encoder->base.id; | 2180 | out_resp->encoder_id = encoder->base.id; |
2070 | else | 2181 | else |
2071 | out_resp->encoder_id = 0; | 2182 | out_resp->encoder_id = 0; |
2072 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
2073 | 2183 | ||
2074 | /* | 2184 | /* |
2075 | * This ioctl is called twice, once to determine how much space is | 2185 | * This ioctl is called twice, once to determine how much space is |
@@ -2093,26 +2203,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2093 | } | 2203 | } |
2094 | out_resp->count_modes = mode_count; | 2204 | out_resp->count_modes = mode_count; |
2095 | 2205 | ||
2096 | if ((out_resp->count_props >= props_count) && props_count) { | 2206 | ret = get_properties(&connector->base, file_priv->atomic, |
2097 | copied = 0; | 2207 | (uint32_t __user *)(unsigned long)(out_resp->props_ptr), |
2098 | prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); | 2208 | (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), |
2099 | prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); | 2209 | &out_resp->count_props); |
2100 | for (i = 0; i < connector->properties.count; i++) { | 2210 | if (ret) |
2101 | if (put_user(connector->properties.ids[i], | 2211 | goto out; |
2102 | prop_ptr + copied)) { | ||
2103 | ret = -EFAULT; | ||
2104 | goto out; | ||
2105 | } | ||
2106 | |||
2107 | if (put_user(connector->properties.values[i], | ||
2108 | prop_values + copied)) { | ||
2109 | ret = -EFAULT; | ||
2110 | goto out; | ||
2111 | } | ||
2112 | copied++; | ||
2113 | } | ||
2114 | } | ||
2115 | out_resp->count_props = props_count; | ||
2116 | 2212 | ||
2117 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { | 2213 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { |
2118 | copied = 0; | 2214 | copied = 0; |
@@ -2131,6 +2227,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
2131 | out_resp->count_encoders = encoders_count; | 2227 | out_resp->count_encoders = encoders_count; |
2132 | 2228 | ||
2133 | out: | 2229 | out: |
2230 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
2134 | mutex_unlock(&dev->mode_config.mutex); | 2231 | mutex_unlock(&dev->mode_config.mutex); |
2135 | 2232 | ||
2136 | return ret; | 2233 | return ret; |
@@ -3823,9 +3920,11 @@ void drm_object_attach_property(struct drm_mode_object *obj, | |||
3823 | return; | 3920 | return; |
3824 | } | 3921 | } |
3825 | 3922 | ||
3826 | obj->properties->ids[count] = property->base.id; | 3923 | obj->properties->properties[count] = property; |
3827 | obj->properties->values[count] = init_val; | 3924 | obj->properties->values[count] = init_val; |
3828 | obj->properties->count++; | 3925 | obj->properties->count++; |
3926 | if (property->flags & DRM_MODE_PROP_ATOMIC) | ||
3927 | obj->properties->atomic_count++; | ||
3829 | } | 3928 | } |
3830 | EXPORT_SYMBOL(drm_object_attach_property); | 3929 | EXPORT_SYMBOL(drm_object_attach_property); |
3831 | 3930 | ||
@@ -3848,7 +3947,7 @@ int drm_object_property_set_value(struct drm_mode_object *obj, | |||
3848 | int i; | 3947 | int i; |
3849 | 3948 | ||
3850 | for (i = 0; i < obj->properties->count; i++) { | 3949 | for (i = 0; i < obj->properties->count; i++) { |
3851 | if (obj->properties->ids[i] == property->base.id) { | 3950 | if (obj->properties->properties[i] == property) { |
3852 | obj->properties->values[i] = val; | 3951 | obj->properties->values[i] = val; |
3853 | return 0; | 3952 | return 0; |
3854 | } | 3953 | } |
@@ -3877,8 +3976,16 @@ int drm_object_property_get_value(struct drm_mode_object *obj, | |||
3877 | { | 3976 | { |
3878 | int i; | 3977 | int i; |
3879 | 3978 | ||
3979 | /* read-only properties bypass atomic mechanism and still store | ||
3980 | * their value in obj->properties->values[].. mostly to avoid | ||
3981 | * having to deal w/ EDID and similar props in atomic paths: | ||
3982 | */ | ||
3983 | if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && | ||
3984 | !(property->flags & DRM_MODE_PROP_IMMUTABLE)) | ||
3985 | return drm_atomic_get_property(obj, property, val); | ||
3986 | |||
3880 | for (i = 0; i < obj->properties->count; i++) { | 3987 | for (i = 0; i < obj->properties->count; i++) { |
3881 | if (obj->properties->ids[i] == property->base.id) { | 3988 | if (obj->properties->properties[i] == property) { |
3882 | *val = obj->properties->values[i]; | 3989 | *val = obj->properties->values[i]; |
3883 | return 0; | 3990 | return 0; |
3884 | } | 3991 | } |
@@ -4194,14 +4301,24 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, | |||
4194 | } | 4301 | } |
4195 | EXPORT_SYMBOL(drm_mode_connector_update_edid_property); | 4302 | EXPORT_SYMBOL(drm_mode_connector_update_edid_property); |
4196 | 4303 | ||
4197 | static bool drm_property_change_is_valid(struct drm_property *property, | 4304 | /* Some properties could refer to dynamic refcnt'd objects, or things that |
4198 | uint64_t value) | 4305 | * need special locking to handle lifetime issues (ie. to ensure the prop |
4306 | * value doesn't become invalid part way through the property update due to | ||
4307 | * race). The value returned by reference via 'obj' should be passed back | ||
4308 | * to drm_property_change_valid_put() after the property is set (and the | ||
4309 | * object to which the property is attached has a chance to take it's own | ||
4310 | * reference). | ||
4311 | */ | ||
4312 | bool drm_property_change_valid_get(struct drm_property *property, | ||
4313 | uint64_t value, struct drm_mode_object **ref) | ||
4199 | { | 4314 | { |
4200 | int i; | 4315 | int i; |
4201 | 4316 | ||
4202 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | 4317 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) |
4203 | return false; | 4318 | return false; |
4204 | 4319 | ||
4320 | *ref = NULL; | ||
4321 | |||
4205 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { | 4322 | if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { |
4206 | if (value < property->values[0] || value > property->values[1]) | 4323 | if (value < property->values[0] || value > property->values[1]) |
4207 | return false; | 4324 | return false; |
@@ -4223,20 +4340,29 @@ static bool drm_property_change_is_valid(struct drm_property *property, | |||
4223 | /* Only the driver knows */ | 4340 | /* Only the driver knows */ |
4224 | return true; | 4341 | return true; |
4225 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | 4342 | } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { |
4226 | struct drm_mode_object *obj; | ||
4227 | |||
4228 | /* a zero value for an object property translates to null: */ | 4343 | /* a zero value for an object property translates to null: */ |
4229 | if (value == 0) | 4344 | if (value == 0) |
4230 | return true; | 4345 | return true; |
4231 | /* | 4346 | |
4232 | * NOTE: use _object_find() directly to bypass restriction on | 4347 | /* handle refcnt'd objects specially: */ |
4233 | * looking up refcnt'd objects (ie. fb's). For a refcnt'd | 4348 | if (property->values[0] == DRM_MODE_OBJECT_FB) { |
4234 | * object this could race against object finalization, so it | 4349 | struct drm_framebuffer *fb; |
4235 | * simply tells us that the object *was* valid. Which is good | 4350 | fb = drm_framebuffer_lookup(property->dev, value); |
4236 | * enough. | 4351 | if (fb) { |
4237 | */ | 4352 | *ref = &fb->base; |
4238 | obj = _object_find(property->dev, value, property->values[0]); | 4353 | return true; |
4239 | return obj != NULL; | 4354 | } else { |
4355 | return false; | ||
4356 | } | ||
4357 | } else { | ||
4358 | return _object_find(property->dev, value, property->values[0]) != NULL; | ||
4359 | } | ||
4360 | } else { | ||
4361 | int i; | ||
4362 | for (i = 0; i < property->num_values; i++) | ||
4363 | if (property->values[i] == value) | ||
4364 | return true; | ||
4365 | return false; | ||
4240 | } | 4366 | } |
4241 | 4367 | ||
4242 | for (i = 0; i < property->num_values; i++) | 4368 | for (i = 0; i < property->num_values; i++) |
@@ -4245,6 +4371,18 @@ static bool drm_property_change_is_valid(struct drm_property *property, | |||
4245 | return false; | 4371 | return false; |
4246 | } | 4372 | } |
4247 | 4373 | ||
4374 | void drm_property_change_valid_put(struct drm_property *property, | ||
4375 | struct drm_mode_object *ref) | ||
4376 | { | ||
4377 | if (!ref) | ||
4378 | return; | ||
4379 | |||
4380 | if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { | ||
4381 | if (property->values[0] == DRM_MODE_OBJECT_FB) | ||
4382 | drm_framebuffer_unreference(obj_to_fb(ref)); | ||
4383 | } | ||
4384 | } | ||
4385 | |||
4248 | /** | 4386 | /** |
4249 | * drm_mode_connector_property_set_ioctl - set the current value of a connector property | 4387 | * drm_mode_connector_property_set_ioctl - set the current value of a connector property |
4250 | * @dev: DRM device | 4388 | * @dev: DRM device |
@@ -4360,11 +4498,6 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
4360 | struct drm_mode_obj_get_properties *arg = data; | 4498 | struct drm_mode_obj_get_properties *arg = data; |
4361 | struct drm_mode_object *obj; | 4499 | struct drm_mode_object *obj; |
4362 | int ret = 0; | 4500 | int ret = 0; |
4363 | int i; | ||
4364 | int copied = 0; | ||
4365 | int props_count = 0; | ||
4366 | uint32_t __user *props_ptr; | ||
4367 | uint64_t __user *prop_values_ptr; | ||
4368 | 4501 | ||
4369 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 4502 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
4370 | return -EINVAL; | 4503 | return -EINVAL; |
@@ -4381,30 +4514,11 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
4381 | goto out; | 4514 | goto out; |
4382 | } | 4515 | } |
4383 | 4516 | ||
4384 | props_count = obj->properties->count; | 4517 | ret = get_properties(obj, file_priv->atomic, |
4518 | (uint32_t __user *)(unsigned long)(arg->props_ptr), | ||
4519 | (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), | ||
4520 | &arg->count_props); | ||
4385 | 4521 | ||
4386 | /* This ioctl is called twice, once to determine how much space is | ||
4387 | * needed, and the 2nd time to fill it. */ | ||
4388 | if ((arg->count_props >= props_count) && props_count) { | ||
4389 | copied = 0; | ||
4390 | props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); | ||
4391 | prop_values_ptr = (uint64_t __user *)(unsigned long) | ||
4392 | (arg->prop_values_ptr); | ||
4393 | for (i = 0; i < props_count; i++) { | ||
4394 | if (put_user(obj->properties->ids[i], | ||
4395 | props_ptr + copied)) { | ||
4396 | ret = -EFAULT; | ||
4397 | goto out; | ||
4398 | } | ||
4399 | if (put_user(obj->properties->values[i], | ||
4400 | prop_values_ptr + copied)) { | ||
4401 | ret = -EFAULT; | ||
4402 | goto out; | ||
4403 | } | ||
4404 | copied++; | ||
4405 | } | ||
4406 | } | ||
4407 | arg->count_props = props_count; | ||
4408 | out: | 4522 | out: |
4409 | drm_modeset_unlock_all(dev); | 4523 | drm_modeset_unlock_all(dev); |
4410 | return ret; | 4524 | return ret; |
@@ -4433,8 +4547,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4433 | struct drm_mode_object *arg_obj; | 4547 | struct drm_mode_object *arg_obj; |
4434 | struct drm_mode_object *prop_obj; | 4548 | struct drm_mode_object *prop_obj; |
4435 | struct drm_property *property; | 4549 | struct drm_property *property; |
4436 | int ret = -EINVAL; | 4550 | int i, ret = -EINVAL; |
4437 | int i; | 4551 | struct drm_mode_object *ref; |
4438 | 4552 | ||
4439 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 4553 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
4440 | return -EINVAL; | 4554 | return -EINVAL; |
@@ -4450,7 +4564,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4450 | goto out; | 4564 | goto out; |
4451 | 4565 | ||
4452 | for (i = 0; i < arg_obj->properties->count; i++) | 4566 | for (i = 0; i < arg_obj->properties->count; i++) |
4453 | if (arg_obj->properties->ids[i] == arg->prop_id) | 4567 | if (arg_obj->properties->properties[i]->base.id == arg->prop_id) |
4454 | break; | 4568 | break; |
4455 | 4569 | ||
4456 | if (i == arg_obj->properties->count) | 4570 | if (i == arg_obj->properties->count) |
@@ -4464,7 +4578,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4464 | } | 4578 | } |
4465 | property = obj_to_property(prop_obj); | 4579 | property = obj_to_property(prop_obj); |
4466 | 4580 | ||
4467 | if (!drm_property_change_is_valid(property, arg->value)) | 4581 | if (!drm_property_change_valid_get(property, arg->value, &ref)) |
4468 | goto out; | 4582 | goto out; |
4469 | 4583 | ||
4470 | switch (arg_obj->type) { | 4584 | switch (arg_obj->type) { |
@@ -4481,6 +4595,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4481 | break; | 4595 | break; |
4482 | } | 4596 | } |
4483 | 4597 | ||
4598 | drm_property_change_valid_put(property, ref); | ||
4599 | |||
4484 | out: | 4600 | out: |
4485 | drm_modeset_unlock_all(dev); | 4601 | drm_modeset_unlock_all(dev); |
4486 | return ret; | 4602 | return ret; |
@@ -5225,8 +5341,7 @@ void drm_mode_config_init(struct drm_device *dev) | |||
5225 | idr_init(&dev->mode_config.tile_idr); | 5341 | idr_init(&dev->mode_config.tile_idr); |
5226 | 5342 | ||
5227 | drm_modeset_lock_all(dev); | 5343 | drm_modeset_lock_all(dev); |
5228 | drm_mode_create_standard_connector_properties(dev); | 5344 | drm_mode_create_standard_properties(dev); |
5229 | drm_mode_create_standard_plane_properties(dev); | ||
5230 | drm_modeset_unlock_all(dev); | 5345 | drm_modeset_unlock_all(dev); |
5231 | 5346 | ||
5232 | /* Just to be sure */ | 5347 | /* Just to be sure */ |