diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
| -rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 581 |
1 files changed, 400 insertions, 181 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e79c8d3700d8..5213da499d39 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
| @@ -683,7 +683,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
| 683 | drm_modeset_lock_init(&crtc->mutex); | 683 | drm_modeset_lock_init(&crtc->mutex); |
| 684 | ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); | 684 | ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); |
| 685 | if (ret) | 685 | if (ret) |
| 686 | goto out; | 686 | return ret; |
| 687 | 687 | ||
| 688 | crtc->base.properties = &crtc->properties; | 688 | crtc->base.properties = &crtc->properties; |
| 689 | 689 | ||
| @@ -697,9 +697,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
| 697 | if (cursor) | 697 | if (cursor) |
| 698 | cursor->possible_crtcs = 1 << drm_crtc_index(crtc); | 698 | cursor->possible_crtcs = 1 << drm_crtc_index(crtc); |
| 699 | 699 | ||
| 700 | out: | 700 | return 0; |
| 701 | |||
| 702 | return ret; | ||
| 703 | } | 701 | } |
| 704 | EXPORT_SYMBOL(drm_crtc_init_with_planes); | 702 | EXPORT_SYMBOL(drm_crtc_init_with_planes); |
| 705 | 703 | ||
| @@ -723,6 +721,12 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) | |||
| 723 | drm_mode_object_put(dev, &crtc->base); | 721 | drm_mode_object_put(dev, &crtc->base); |
| 724 | list_del(&crtc->head); | 722 | list_del(&crtc->head); |
| 725 | dev->mode_config.num_crtc--; | 723 | dev->mode_config.num_crtc--; |
| 724 | |||
| 725 | WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); | ||
| 726 | if (crtc->state && crtc->funcs->atomic_destroy_state) | ||
| 727 | crtc->funcs->atomic_destroy_state(crtc, crtc->state); | ||
| 728 | |||
| 729 | memset(crtc, 0, sizeof(*crtc)); | ||
| 726 | } | 730 | } |
| 727 | EXPORT_SYMBOL(drm_crtc_cleanup); | 731 | EXPORT_SYMBOL(drm_crtc_cleanup); |
| 728 | 732 | ||
| @@ -766,7 +770,6 @@ static void drm_mode_remove(struct drm_connector *connector, | |||
| 766 | /** | 770 | /** |
| 767 | * drm_connector_get_cmdline_mode - reads the user's cmdline mode | 771 | * drm_connector_get_cmdline_mode - reads the user's cmdline mode |
| 768 | * @connector: connector to quwery | 772 | * @connector: connector to quwery |
| 769 | * @mode: returned mode | ||
| 770 | * | 773 | * |
| 771 | * The kernel supports per-connector configration of its consoles through | 774 | * The kernel supports per-connector configration of its consoles through |
| 772 | * use of the video= parameter. This function parses that option and | 775 | * use of the video= parameter. This function parses that option and |
| @@ -870,6 +873,8 @@ int drm_connector_init(struct drm_device *dev, | |||
| 870 | 873 | ||
| 871 | drm_connector_get_cmdline_mode(connector); | 874 | drm_connector_get_cmdline_mode(connector); |
| 872 | 875 | ||
| 876 | /* We should add connectors at the end to avoid upsetting the connector | ||
| 877 | * index too much. */ | ||
| 873 | list_add_tail(&connector->head, &dev->mode_config.connector_list); | 878 | list_add_tail(&connector->head, &dev->mode_config.connector_list); |
| 874 | dev->mode_config.num_connector++; | 879 | dev->mode_config.num_connector++; |
| 875 | 880 | ||
| @@ -905,6 +910,11 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
| 905 | struct drm_device *dev = connector->dev; | 910 | struct drm_device *dev = connector->dev; |
| 906 | struct drm_display_mode *mode, *t; | 911 | struct drm_display_mode *mode, *t; |
| 907 | 912 | ||
| 913 | if (connector->tile_group) { | ||
| 914 | drm_mode_put_tile_group(dev, connector->tile_group); | ||
| 915 | connector->tile_group = NULL; | ||
| 916 | } | ||
| 917 | |||
| 908 | list_for_each_entry_safe(mode, t, &connector->probed_modes, head) | 918 | list_for_each_entry_safe(mode, t, &connector->probed_modes, head) |
| 909 | drm_mode_remove(connector, mode); | 919 | drm_mode_remove(connector, mode); |
| 910 | 920 | ||
| @@ -919,6 +929,13 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
| 919 | connector->name = NULL; | 929 | connector->name = NULL; |
| 920 | list_del(&connector->head); | 930 | list_del(&connector->head); |
| 921 | dev->mode_config.num_connector--; | 931 | dev->mode_config.num_connector--; |
| 932 | |||
| 933 | WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); | ||
| 934 | if (connector->state && connector->funcs->atomic_destroy_state) | ||
| 935 | connector->funcs->atomic_destroy_state(connector, | ||
| 936 | connector->state); | ||
| 937 | |||
| 938 | memset(connector, 0, sizeof(*connector)); | ||
| 922 | } | 939 | } |
| 923 | EXPORT_SYMBOL(drm_connector_cleanup); | 940 | EXPORT_SYMBOL(drm_connector_cleanup); |
| 924 | 941 | ||
| @@ -933,6 +950,9 @@ unsigned int drm_connector_index(struct drm_connector *connector) | |||
| 933 | { | 950 | { |
| 934 | unsigned int index = 0; | 951 | unsigned int index = 0; |
| 935 | struct drm_connector *tmp; | 952 | struct drm_connector *tmp; |
| 953 | struct drm_mode_config *config = &connector->dev->mode_config; | ||
| 954 | |||
| 955 | WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); | ||
| 936 | 956 | ||
| 937 | list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { | 957 | list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { |
| 938 | if (tmp == connector) | 958 | if (tmp == connector) |
| @@ -1057,6 +1077,8 @@ void drm_bridge_cleanup(struct drm_bridge *bridge) | |||
| 1057 | list_del(&bridge->head); | 1077 | list_del(&bridge->head); |
| 1058 | dev->mode_config.num_bridge--; | 1078 | dev->mode_config.num_bridge--; |
| 1059 | drm_modeset_unlock_all(dev); | 1079 | drm_modeset_unlock_all(dev); |
| 1080 | |||
| 1081 | memset(bridge, 0, sizeof(*bridge)); | ||
| 1060 | } | 1082 | } |
| 1061 | EXPORT_SYMBOL(drm_bridge_cleanup); | 1083 | EXPORT_SYMBOL(drm_bridge_cleanup); |
| 1062 | 1084 | ||
| @@ -1123,10 +1145,11 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) | |||
| 1123 | drm_modeset_lock_all(dev); | 1145 | drm_modeset_lock_all(dev); |
| 1124 | drm_mode_object_put(dev, &encoder->base); | 1146 | drm_mode_object_put(dev, &encoder->base); |
| 1125 | kfree(encoder->name); | 1147 | kfree(encoder->name); |
| 1126 | encoder->name = NULL; | ||
| 1127 | list_del(&encoder->head); | 1148 | list_del(&encoder->head); |
| 1128 | dev->mode_config.num_encoder--; | 1149 | dev->mode_config.num_encoder--; |
| 1129 | drm_modeset_unlock_all(dev); | 1150 | drm_modeset_unlock_all(dev); |
| 1151 | |||
| 1152 | memset(encoder, 0, sizeof(*encoder)); | ||
| 1130 | } | 1153 | } |
| 1131 | EXPORT_SYMBOL(drm_encoder_cleanup); | 1154 | EXPORT_SYMBOL(drm_encoder_cleanup); |
| 1132 | 1155 | ||
| @@ -1153,11 +1176,11 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
| 1153 | { | 1176 | { |
| 1154 | int ret; | 1177 | int ret; |
| 1155 | 1178 | ||
| 1156 | drm_modeset_lock_all(dev); | ||
| 1157 | |||
| 1158 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | 1179 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); |
| 1159 | if (ret) | 1180 | if (ret) |
| 1160 | goto out; | 1181 | return ret; |
| 1182 | |||
| 1183 | drm_modeset_lock_init(&plane->mutex); | ||
| 1161 | 1184 | ||
| 1162 | plane->base.properties = &plane->properties; | 1185 | plane->base.properties = &plane->properties; |
| 1163 | plane->dev = dev; | 1186 | plane->dev = dev; |
| @@ -1167,8 +1190,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
| 1167 | if (!plane->format_types) { | 1190 | if (!plane->format_types) { |
| 1168 | DRM_DEBUG_KMS("out of memory when allocating plane\n"); | 1191 | DRM_DEBUG_KMS("out of memory when allocating plane\n"); |
| 1169 | drm_mode_object_put(dev, &plane->base); | 1192 | drm_mode_object_put(dev, &plane->base); |
| 1170 | ret = -ENOMEM; | 1193 | return -ENOMEM; |
| 1171 | goto out; | ||
| 1172 | } | 1194 | } |
| 1173 | 1195 | ||
| 1174 | memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); | 1196 | memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); |
| @@ -1185,10 +1207,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
| 1185 | dev->mode_config.plane_type_property, | 1207 | dev->mode_config.plane_type_property, |
| 1186 | plane->type); | 1208 | plane->type); |
| 1187 | 1209 | ||
| 1188 | out: | 1210 | return 0; |
| 1189 | drm_modeset_unlock_all(dev); | ||
| 1190 | |||
| 1191 | return ret; | ||
| 1192 | } | 1211 | } |
| 1193 | EXPORT_SYMBOL(drm_universal_plane_init); | 1212 | EXPORT_SYMBOL(drm_universal_plane_init); |
| 1194 | 1213 | ||
| @@ -1246,6 +1265,12 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
| 1246 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | 1265 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) |
| 1247 | dev->mode_config.num_overlay_plane--; | 1266 | dev->mode_config.num_overlay_plane--; |
| 1248 | drm_modeset_unlock_all(dev); | 1267 | drm_modeset_unlock_all(dev); |
| 1268 | |||
| 1269 | WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); | ||
| 1270 | if (plane->state && plane->funcs->atomic_destroy_state) | ||
| 1271 | plane->funcs->atomic_destroy_state(plane, plane->state); | ||
| 1272 | |||
| 1273 | memset(plane, 0, sizeof(*plane)); | ||
| 1249 | } | 1274 | } |
| 1250 | EXPORT_SYMBOL(drm_plane_cleanup); | 1275 | EXPORT_SYMBOL(drm_plane_cleanup); |
| 1251 | 1276 | ||
| @@ -1328,6 +1353,11 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) | |||
| 1328 | "PATH", 0); | 1353 | "PATH", 0); |
| 1329 | dev->mode_config.path_property = dev_path; | 1354 | dev->mode_config.path_property = dev_path; |
| 1330 | 1355 | ||
| 1356 | dev->mode_config.tile_property = drm_property_create(dev, | ||
| 1357 | DRM_MODE_PROP_BLOB | | ||
| 1358 | DRM_MODE_PROP_IMMUTABLE, | ||
| 1359 | "TILE", 0); | ||
| 1360 | |||
| 1331 | return 0; | 1361 | return 0; |
| 1332 | } | 1362 | } |
| 1333 | 1363 | ||
| @@ -1388,12 +1418,13 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); | |||
| 1388 | * responsible for allocating a list of format names and passing them to | 1418 | * responsible for allocating a list of format names and passing them to |
| 1389 | * this routine. | 1419 | * this routine. |
| 1390 | */ | 1420 | */ |
| 1391 | int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, | 1421 | int drm_mode_create_tv_properties(struct drm_device *dev, |
| 1422 | unsigned int num_modes, | ||
| 1392 | char *modes[]) | 1423 | char *modes[]) |
| 1393 | { | 1424 | { |
| 1394 | struct drm_property *tv_selector; | 1425 | struct drm_property *tv_selector; |
| 1395 | struct drm_property *tv_subconnector; | 1426 | struct drm_property *tv_subconnector; |
| 1396 | int i; | 1427 | unsigned int i; |
| 1397 | 1428 | ||
| 1398 | if (dev->mode_config.tv_select_subconnector_property) | 1429 | if (dev->mode_config.tv_select_subconnector_property) |
| 1399 | return 0; | 1430 | return 0; |
| @@ -1491,7 +1522,7 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); | |||
| 1491 | * connectors. | 1522 | * connectors. |
| 1492 | * | 1523 | * |
| 1493 | * Returns: | 1524 | * Returns: |
| 1494 | * Zero on success, errno on failure. | 1525 | * Zero on success, negative errno on failure. |
| 1495 | */ | 1526 | */ |
| 1496 | int drm_mode_create_aspect_ratio_property(struct drm_device *dev) | 1527 | int drm_mode_create_aspect_ratio_property(struct drm_device *dev) |
| 1497 | { | 1528 | { |
| @@ -1535,6 +1566,30 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev) | |||
| 1535 | } | 1566 | } |
| 1536 | EXPORT_SYMBOL(drm_mode_create_dirty_info_property); | 1567 | EXPORT_SYMBOL(drm_mode_create_dirty_info_property); |
| 1537 | 1568 | ||
| 1569 | /** | ||
| 1570 | * drm_mode_create_suggested_offset_properties - create suggests offset properties | ||
| 1571 | * @dev: DRM device | ||
| 1572 | * | ||
| 1573 | * Create the the suggested x/y offset property for connectors. | ||
| 1574 | */ | ||
| 1575 | int drm_mode_create_suggested_offset_properties(struct drm_device *dev) | ||
| 1576 | { | ||
| 1577 | if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) | ||
| 1578 | return 0; | ||
| 1579 | |||
| 1580 | dev->mode_config.suggested_x_property = | ||
| 1581 | drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); | ||
| 1582 | |||
| 1583 | dev->mode_config.suggested_y_property = | ||
| 1584 | drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); | ||
| 1585 | |||
| 1586 | if (dev->mode_config.suggested_x_property == NULL || | ||
| 1587 | dev->mode_config.suggested_y_property == NULL) | ||
| 1588 | return -ENOMEM; | ||
| 1589 | return 0; | ||
| 1590 | } | ||
| 1591 | EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); | ||
| 1592 | |||
| 1538 | static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) | 1593 | static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) |
| 1539 | { | 1594 | { |
| 1540 | uint32_t total_objects = 0; | 1595 | uint32_t total_objects = 0; |
| @@ -1651,7 +1706,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, | |||
| 1651 | * the caller. | 1706 | * the caller. |
| 1652 | * | 1707 | * |
| 1653 | * Returns: | 1708 | * Returns: |
| 1654 | * Zero on success, errno on failure. | 1709 | * Zero on success, negative errno on failure. |
| 1655 | */ | 1710 | */ |
| 1656 | static int drm_crtc_convert_umode(struct drm_display_mode *out, | 1711 | static int drm_crtc_convert_umode(struct drm_display_mode *out, |
| 1657 | const struct drm_mode_modeinfo *in) | 1712 | const struct drm_mode_modeinfo *in) |
| @@ -1694,7 +1749,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, | |||
| 1694 | * Called by the user via ioctl. | 1749 | * Called by the user via ioctl. |
| 1695 | * | 1750 | * |
| 1696 | * Returns: | 1751 | * Returns: |
| 1697 | * Zero on success, errno on failure. | 1752 | * Zero on success, negative errno on failure. |
| 1698 | */ | 1753 | */ |
| 1699 | int drm_mode_getresources(struct drm_device *dev, void *data, | 1754 | int drm_mode_getresources(struct drm_device *dev, void *data, |
| 1700 | struct drm_file *file_priv) | 1755 | struct drm_file *file_priv) |
| @@ -1745,7 +1800,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, | |||
| 1745 | card_res->count_fbs = fb_count; | 1800 | card_res->count_fbs = fb_count; |
| 1746 | mutex_unlock(&file_priv->fbs_lock); | 1801 | mutex_unlock(&file_priv->fbs_lock); |
| 1747 | 1802 | ||
| 1748 | drm_modeset_lock_all(dev); | 1803 | /* mode_config.mutex protects the connector list against e.g. DP MST |
| 1804 | * connector hot-adding. CRTC/Plane lists are invariant. */ | ||
| 1805 | mutex_lock(&dev->mode_config.mutex); | ||
| 1749 | if (!drm_is_primary_client(file_priv)) { | 1806 | if (!drm_is_primary_client(file_priv)) { |
| 1750 | 1807 | ||
| 1751 | mode_group = NULL; | 1808 | mode_group = NULL; |
| @@ -1865,7 +1922,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, | |||
| 1865 | card_res->count_connectors, card_res->count_encoders); | 1922 | card_res->count_connectors, card_res->count_encoders); |
| 1866 | 1923 | ||
| 1867 | out: | 1924 | out: |
| 1868 | drm_modeset_unlock_all(dev); | 1925 | mutex_unlock(&dev->mode_config.mutex); |
| 1869 | return ret; | 1926 | return ret; |
| 1870 | } | 1927 | } |
| 1871 | 1928 | ||
| @@ -1880,26 +1937,22 @@ out: | |||
| 1880 | * Called by the user via ioctl. | 1937 | * Called by the user via ioctl. |
| 1881 | * | 1938 | * |
| 1882 | * Returns: | 1939 | * Returns: |
| 1883 | * Zero on success, errno on failure. | 1940 | * Zero on success, negative errno on failure. |
| 1884 | */ | 1941 | */ |
| 1885 | int drm_mode_getcrtc(struct drm_device *dev, | 1942 | int drm_mode_getcrtc(struct drm_device *dev, |
| 1886 | void *data, struct drm_file *file_priv) | 1943 | void *data, struct drm_file *file_priv) |
| 1887 | { | 1944 | { |
| 1888 | struct drm_mode_crtc *crtc_resp = data; | 1945 | struct drm_mode_crtc *crtc_resp = data; |
| 1889 | struct drm_crtc *crtc; | 1946 | struct drm_crtc *crtc; |
| 1890 | int ret = 0; | ||
| 1891 | 1947 | ||
| 1892 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1948 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 1893 | return -EINVAL; | 1949 | return -EINVAL; |
| 1894 | 1950 | ||
| 1895 | drm_modeset_lock_all(dev); | ||
| 1896 | |||
| 1897 | crtc = drm_crtc_find(dev, crtc_resp->crtc_id); | 1951 | crtc = drm_crtc_find(dev, crtc_resp->crtc_id); |
| 1898 | if (!crtc) { | 1952 | if (!crtc) |
| 1899 | ret = -ENOENT; | 1953 | return -ENOENT; |
| 1900 | goto out; | ||
| 1901 | } | ||
| 1902 | 1954 | ||
| 1955 | drm_modeset_lock_crtc(crtc, crtc->primary); | ||
| 1903 | crtc_resp->x = crtc->x; | 1956 | crtc_resp->x = crtc->x; |
| 1904 | crtc_resp->y = crtc->y; | 1957 | crtc_resp->y = crtc->y; |
| 1905 | crtc_resp->gamma_size = crtc->gamma_size; | 1958 | crtc_resp->gamma_size = crtc->gamma_size; |
| @@ -1916,10 +1969,9 @@ int drm_mode_getcrtc(struct drm_device *dev, | |||
| 1916 | } else { | 1969 | } else { |
| 1917 | crtc_resp->mode_valid = 0; | 1970 | crtc_resp->mode_valid = 0; |
| 1918 | } | 1971 | } |
| 1972 | drm_modeset_unlock_crtc(crtc); | ||
| 1919 | 1973 | ||
| 1920 | out: | 1974 | return 0; |
| 1921 | drm_modeset_unlock_all(dev); | ||
| 1922 | return ret; | ||
| 1923 | } | 1975 | } |
| 1924 | 1976 | ||
| 1925 | static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, | 1977 | static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, |
| @@ -1935,6 +1987,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, | |||
| 1935 | return true; | 1987 | return true; |
| 1936 | } | 1988 | } |
| 1937 | 1989 | ||
| 1990 | static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) | ||
| 1991 | { | ||
| 1992 | /* For atomic drivers only state objects are synchronously updated and | ||
| 1993 | * protected by modeset locks, so check those first. */ | ||
| 1994 | if (connector->state) | ||
| 1995 | return connector->state->best_encoder; | ||
| 1996 | return connector->encoder; | ||
| 1997 | } | ||
| 1998 | |||
| 1938 | /** | 1999 | /** |
| 1939 | * drm_mode_getconnector - get connector configuration | 2000 | * drm_mode_getconnector - get connector configuration |
| 1940 | * @dev: drm device for the ioctl | 2001 | * @dev: drm device for the ioctl |
| @@ -1946,13 +2007,14 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, | |||
| 1946 | * Called by the user via ioctl. | 2007 | * Called by the user via ioctl. |
| 1947 | * | 2008 | * |
| 1948 | * Returns: | 2009 | * Returns: |
| 1949 | * Zero on success, errno on failure. | 2010 | * Zero on success, negative errno on failure. |
| 1950 | */ | 2011 | */ |
| 1951 | int drm_mode_getconnector(struct drm_device *dev, void *data, | 2012 | int drm_mode_getconnector(struct drm_device *dev, void *data, |
| 1952 | struct drm_file *file_priv) | 2013 | struct drm_file *file_priv) |
| 1953 | { | 2014 | { |
| 1954 | struct drm_mode_get_connector *out_resp = data; | 2015 | struct drm_mode_get_connector *out_resp = data; |
| 1955 | struct drm_connector *connector; | 2016 | struct drm_connector *connector; |
| 2017 | struct drm_encoder *encoder; | ||
| 1956 | struct drm_display_mode *mode; | 2018 | struct drm_display_mode *mode; |
| 1957 | int mode_count = 0; | 2019 | int mode_count = 0; |
| 1958 | int props_count = 0; | 2020 | int props_count = 0; |
| @@ -2008,8 +2070,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
| 2008 | out_resp->subpixel = connector->display_info.subpixel_order; | 2070 | out_resp->subpixel = connector->display_info.subpixel_order; |
| 2009 | out_resp->connection = connector->status; | 2071 | out_resp->connection = connector->status; |
| 2010 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); | 2072 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
| 2011 | if (connector->encoder) | 2073 | |
| 2012 | out_resp->encoder_id = connector->encoder->base.id; | 2074 | encoder = drm_connector_get_encoder(connector); |
| 2075 | if (encoder) | ||
| 2076 | out_resp->encoder_id = encoder->base.id; | ||
| 2013 | else | 2077 | else |
| 2014 | out_resp->encoder_id = 0; | 2078 | out_resp->encoder_id = 0; |
| 2015 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | 2079 | drm_modeset_unlock(&dev->mode_config.connection_mutex); |
| @@ -2079,6 +2143,33 @@ out: | |||
| 2079 | return ret; | 2143 | return ret; |
| 2080 | } | 2144 | } |
| 2081 | 2145 | ||
| 2146 | static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) | ||
| 2147 | { | ||
| 2148 | struct drm_connector *connector; | ||
| 2149 | struct drm_device *dev = encoder->dev; | ||
| 2150 | bool uses_atomic = false; | ||
| 2151 | |||
| 2152 | /* For atomic drivers only state objects are synchronously updated and | ||
| 2153 | * protected by modeset locks, so check those first. */ | ||
| 2154 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 2155 | if (!connector->state) | ||
| 2156 | continue; | ||
| 2157 | |||
| 2158 | uses_atomic = true; | ||
| 2159 | |||
| 2160 | if (connector->state->best_encoder != encoder) | ||
| 2161 | continue; | ||
| 2162 | |||
| 2163 | return connector->state->crtc; | ||
| 2164 | } | ||
| 2165 | |||
| 2166 | /* Don't return stale data (e.g. pending async disable). */ | ||
| 2167 | if (uses_atomic) | ||
| 2168 | return NULL; | ||
| 2169 | |||
| 2170 | return encoder->crtc; | ||
| 2171 | } | ||
| 2172 | |||
| 2082 | /** | 2173 | /** |
| 2083 | * drm_mode_getencoder - get encoder configuration | 2174 | * drm_mode_getencoder - get encoder configuration |
| 2084 | * @dev: drm device for the ioctl | 2175 | * @dev: drm device for the ioctl |
| @@ -2090,37 +2181,38 @@ out: | |||
| 2090 | * Called by the user via ioctl. | 2181 | * Called by the user via ioctl. |
| 2091 | * | 2182 | * |
| 2092 | * Returns: | 2183 | * Returns: |
| 2093 | * Zero on success, errno on failure. | 2184 | * Zero on success, negative errno on failure. |
| 2094 | */ | 2185 | */ |
| 2095 | int drm_mode_getencoder(struct drm_device *dev, void *data, | 2186 | int drm_mode_getencoder(struct drm_device *dev, void *data, |
| 2096 | struct drm_file *file_priv) | 2187 | struct drm_file *file_priv) |
| 2097 | { | 2188 | { |
| 2098 | struct drm_mode_get_encoder *enc_resp = data; | 2189 | struct drm_mode_get_encoder *enc_resp = data; |
| 2099 | struct drm_encoder *encoder; | 2190 | struct drm_encoder *encoder; |
| 2100 | int ret = 0; | 2191 | struct drm_crtc *crtc; |
| 2101 | 2192 | ||
| 2102 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2193 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 2103 | return -EINVAL; | 2194 | return -EINVAL; |
| 2104 | 2195 | ||
| 2105 | drm_modeset_lock_all(dev); | ||
| 2106 | encoder = drm_encoder_find(dev, enc_resp->encoder_id); | 2196 | encoder = drm_encoder_find(dev, enc_resp->encoder_id); |
| 2107 | if (!encoder) { | 2197 | if (!encoder) |
| 2108 | ret = -ENOENT; | 2198 | return -ENOENT; |
| 2109 | goto out; | ||
| 2110 | } | ||
| 2111 | 2199 | ||
| 2112 | if (encoder->crtc) | 2200 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
| 2201 | crtc = drm_encoder_get_crtc(encoder); | ||
| 2202 | if (crtc) | ||
| 2203 | enc_resp->crtc_id = crtc->base.id; | ||
| 2204 | else if (encoder->crtc) | ||
| 2113 | enc_resp->crtc_id = encoder->crtc->base.id; | 2205 | enc_resp->crtc_id = encoder->crtc->base.id; |
| 2114 | else | 2206 | else |
| 2115 | enc_resp->crtc_id = 0; | 2207 | enc_resp->crtc_id = 0; |
| 2208 | drm_modeset_unlock(&dev->mode_config.connection_mutex); | ||
| 2209 | |||
| 2116 | enc_resp->encoder_type = encoder->encoder_type; | 2210 | enc_resp->encoder_type = encoder->encoder_type; |
| 2117 | enc_resp->encoder_id = encoder->base.id; | 2211 | enc_resp->encoder_id = encoder->base.id; |
| 2118 | enc_resp->possible_crtcs = encoder->possible_crtcs; | 2212 | enc_resp->possible_crtcs = encoder->possible_crtcs; |
| 2119 | enc_resp->possible_clones = encoder->possible_clones; | 2213 | enc_resp->possible_clones = encoder->possible_clones; |
| 2120 | 2214 | ||
| 2121 | out: | 2215 | return 0; |
| 2122 | drm_modeset_unlock_all(dev); | ||
| 2123 | return ret; | ||
| 2124 | } | 2216 | } |
| 2125 | 2217 | ||
| 2126 | /** | 2218 | /** |
| @@ -2134,7 +2226,7 @@ out: | |||
| 2134 | * Called by the user via ioctl. | 2226 | * Called by the user via ioctl. |
| 2135 | * | 2227 | * |
| 2136 | * Returns: | 2228 | * Returns: |
| 2137 | * Zero on success, errno on failure. | 2229 | * Zero on success, negative errno on failure. |
| 2138 | */ | 2230 | */ |
| 2139 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | 2231 | int drm_mode_getplane_res(struct drm_device *dev, void *data, |
| 2140 | struct drm_file *file_priv) | 2232 | struct drm_file *file_priv) |
| @@ -2143,13 +2235,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, | |||
| 2143 | struct drm_mode_config *config; | 2235 | struct drm_mode_config *config; |
| 2144 | struct drm_plane *plane; | 2236 | struct drm_plane *plane; |
| 2145 | uint32_t __user *plane_ptr; | 2237 | uint32_t __user *plane_ptr; |
| 2146 | int copied = 0, ret = 0; | 2238 | int copied = 0; |
| 2147 | unsigned num_planes; | 2239 | unsigned num_planes; |
| 2148 | 2240 | ||
| 2149 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2241 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 2150 | return -EINVAL; | 2242 | return -EINVAL; |
| 2151 | 2243 | ||
| 2152 | drm_modeset_lock_all(dev); | ||
| 2153 | config = &dev->mode_config; | 2244 | config = &dev->mode_config; |
| 2154 | 2245 | ||
| 2155 | if (file_priv->universal_planes) | 2246 | if (file_priv->universal_planes) |
| @@ -2165,6 +2256,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, | |||
| 2165 | (plane_resp->count_planes >= num_planes)) { | 2256 | (plane_resp->count_planes >= num_planes)) { |
| 2166 | plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; | 2257 | plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; |
| 2167 | 2258 | ||
| 2259 | /* Plane lists are invariant, no locking needed. */ | ||
| 2168 | list_for_each_entry(plane, &config->plane_list, head) { | 2260 | list_for_each_entry(plane, &config->plane_list, head) { |
| 2169 | /* | 2261 | /* |
| 2170 | * Unless userspace set the 'universal planes' | 2262 | * Unless userspace set the 'universal planes' |
| @@ -2174,18 +2266,14 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, | |||
| 2174 | !file_priv->universal_planes) | 2266 | !file_priv->universal_planes) |
| 2175 | continue; | 2267 | continue; |
| 2176 | 2268 | ||
| 2177 | if (put_user(plane->base.id, plane_ptr + copied)) { | 2269 | if (put_user(plane->base.id, plane_ptr + copied)) |
| 2178 | ret = -EFAULT; | 2270 | return -EFAULT; |
| 2179 | goto out; | ||
| 2180 | } | ||
| 2181 | copied++; | 2271 | copied++; |
| 2182 | } | 2272 | } |
| 2183 | } | 2273 | } |
| 2184 | plane_resp->count_planes = num_planes; | 2274 | plane_resp->count_planes = num_planes; |
| 2185 | 2275 | ||
| 2186 | out: | 2276 | return 0; |
| 2187 | drm_modeset_unlock_all(dev); | ||
| 2188 | return ret; | ||
| 2189 | } | 2277 | } |
| 2190 | 2278 | ||
| 2191 | /** | 2279 | /** |
| @@ -2199,7 +2287,7 @@ out: | |||
| 2199 | * Called by the user via ioctl. | 2287 | * Called by the user via ioctl. |
| 2200 | * | 2288 | * |
| 2201 | * Returns: | 2289 | * Returns: |
| 2202 | * Zero on success, errno on failure. | 2290 | * Zero on success, negative errno on failure. |
| 2203 | */ | 2291 | */ |
| 2204 | int drm_mode_getplane(struct drm_device *dev, void *data, | 2292 | int drm_mode_getplane(struct drm_device *dev, void *data, |
| 2205 | struct drm_file *file_priv) | 2293 | struct drm_file *file_priv) |
| @@ -2207,18 +2295,15 @@ int drm_mode_getplane(struct drm_device *dev, void *data, | |||
| 2207 | struct drm_mode_get_plane *plane_resp = data; | 2295 | struct drm_mode_get_plane *plane_resp = data; |
| 2208 | struct drm_plane *plane; | 2296 | struct drm_plane *plane; |
| 2209 | uint32_t __user *format_ptr; | 2297 | uint32_t __user *format_ptr; |
| 2210 | int ret = 0; | ||
| 2211 | 2298 | ||
| 2212 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2299 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 2213 | return -EINVAL; | 2300 | return -EINVAL; |
| 2214 | 2301 | ||
| 2215 | drm_modeset_lock_all(dev); | ||
| 2216 | plane = drm_plane_find(dev, plane_resp->plane_id); | 2302 | plane = drm_plane_find(dev, plane_resp->plane_id); |
| 2217 | if (!plane) { | 2303 | if (!plane) |
| 2218 | ret = -ENOENT; | 2304 | return -ENOENT; |
| 2219 | goto out; | ||
| 2220 | } | ||
| 2221 | 2305 | ||
| 2306 | drm_modeset_lock(&plane->mutex, NULL); | ||
| 2222 | if (plane->crtc) | 2307 | if (plane->crtc) |
| 2223 | plane_resp->crtc_id = plane->crtc->base.id; | 2308 | plane_resp->crtc_id = plane->crtc->base.id; |
| 2224 | else | 2309 | else |
| @@ -2228,6 +2313,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, | |||
| 2228 | plane_resp->fb_id = plane->fb->base.id; | 2313 | plane_resp->fb_id = plane->fb->base.id; |
| 2229 | else | 2314 | else |
| 2230 | plane_resp->fb_id = 0; | 2315 | plane_resp->fb_id = 0; |
| 2316 | drm_modeset_unlock(&plane->mutex); | ||
| 2231 | 2317 | ||
| 2232 | plane_resp->plane_id = plane->base.id; | 2318 | plane_resp->plane_id = plane->base.id; |
| 2233 | plane_resp->possible_crtcs = plane->possible_crtcs; | 2319 | plane_resp->possible_crtcs = plane->possible_crtcs; |
| @@ -2243,15 +2329,12 @@ int drm_mode_getplane(struct drm_device *dev, void *data, | |||
| 2243 | if (copy_to_user(format_ptr, | 2329 | if (copy_to_user(format_ptr, |
| 2244 | plane->format_types, | 2330 | plane->format_types, |
| 2245 | sizeof(uint32_t) * plane->format_count)) { | 2331 | sizeof(uint32_t) * plane->format_count)) { |
| 2246 | ret = -EFAULT; | 2332 | return -EFAULT; |
| 2247 | goto out; | ||
| 2248 | } | 2333 | } |
| 2249 | } | 2334 | } |
| 2250 | plane_resp->count_format_types = plane->format_count; | 2335 | plane_resp->count_format_types = plane->format_count; |
| 2251 | 2336 | ||
| 2252 | out: | 2337 | return 0; |
| 2253 | drm_modeset_unlock_all(dev); | ||
| 2254 | return ret; | ||
| 2255 | } | 2338 | } |
| 2256 | 2339 | ||
| 2257 | /* | 2340 | /* |
| @@ -2274,7 +2357,7 @@ static int __setplane_internal(struct drm_plane *plane, | |||
| 2274 | { | 2357 | { |
| 2275 | int ret = 0; | 2358 | int ret = 0; |
| 2276 | unsigned int fb_width, fb_height; | 2359 | unsigned int fb_width, fb_height; |
| 2277 | int i; | 2360 | unsigned int i; |
| 2278 | 2361 | ||
| 2279 | /* No fb means shut it down */ | 2362 | /* No fb means shut it down */ |
| 2280 | if (!fb) { | 2363 | if (!fb) { |
| @@ -2378,13 +2461,12 @@ static int setplane_internal(struct drm_plane *plane, | |||
| 2378 | * valid crtc). | 2461 | * valid crtc). |
| 2379 | * | 2462 | * |
| 2380 | * Returns: | 2463 | * Returns: |
| 2381 | * Zero on success, errno on failure. | 2464 | * Zero on success, negative errno on failure. |
| 2382 | */ | 2465 | */ |
| 2383 | int drm_mode_setplane(struct drm_device *dev, void *data, | 2466 | int drm_mode_setplane(struct drm_device *dev, void *data, |
| 2384 | struct drm_file *file_priv) | 2467 | struct drm_file *file_priv) |
| 2385 | { | 2468 | { |
| 2386 | struct drm_mode_set_plane *plane_req = data; | 2469 | struct drm_mode_set_plane *plane_req = data; |
| 2387 | struct drm_mode_object *obj; | ||
| 2388 | struct drm_plane *plane; | 2470 | struct drm_plane *plane; |
| 2389 | struct drm_crtc *crtc = NULL; | 2471 | struct drm_crtc *crtc = NULL; |
| 2390 | struct drm_framebuffer *fb = NULL; | 2472 | struct drm_framebuffer *fb = NULL; |
| @@ -2407,14 +2489,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
| 2407 | * First, find the plane, crtc, and fb objects. If not available, | 2489 | * First, find the plane, crtc, and fb objects. If not available, |
| 2408 | * we don't bother to call the driver. | 2490 | * we don't bother to call the driver. |
| 2409 | */ | 2491 | */ |
| 2410 | obj = drm_mode_object_find(dev, plane_req->plane_id, | 2492 | plane = drm_plane_find(dev, plane_req->plane_id); |
| 2411 | DRM_MODE_OBJECT_PLANE); | 2493 | if (!plane) { |
| 2412 | if (!obj) { | ||
| 2413 | DRM_DEBUG_KMS("Unknown plane ID %d\n", | 2494 | DRM_DEBUG_KMS("Unknown plane ID %d\n", |
| 2414 | plane_req->plane_id); | 2495 | plane_req->plane_id); |
| 2415 | return -ENOENT; | 2496 | return -ENOENT; |
| 2416 | } | 2497 | } |
| 2417 | plane = obj_to_plane(obj); | ||
| 2418 | 2498 | ||
| 2419 | if (plane_req->fb_id) { | 2499 | if (plane_req->fb_id) { |
| 2420 | fb = drm_framebuffer_lookup(dev, plane_req->fb_id); | 2500 | fb = drm_framebuffer_lookup(dev, plane_req->fb_id); |
| @@ -2424,14 +2504,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
| 2424 | return -ENOENT; | 2504 | return -ENOENT; |
| 2425 | } | 2505 | } |
| 2426 | 2506 | ||
| 2427 | obj = drm_mode_object_find(dev, plane_req->crtc_id, | 2507 | crtc = drm_crtc_find(dev, plane_req->crtc_id); |
| 2428 | DRM_MODE_OBJECT_CRTC); | 2508 | if (!crtc) { |
| 2429 | if (!obj) { | ||
| 2430 | DRM_DEBUG_KMS("Unknown crtc ID %d\n", | 2509 | DRM_DEBUG_KMS("Unknown crtc ID %d\n", |
| 2431 | plane_req->crtc_id); | 2510 | plane_req->crtc_id); |
| 2432 | return -ENOENT; | 2511 | return -ENOENT; |
| 2433 | } | 2512 | } |
| 2434 | crtc = obj_to_crtc(obj); | ||
| 2435 | } | 2513 | } |
| 2436 | 2514 | ||
| 2437 | /* | 2515 | /* |
| @@ -2453,7 +2531,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
| 2453 | * interface. The only thing it adds is correct refcounting dance. | 2531 | * interface. The only thing it adds is correct refcounting dance. |
| 2454 | * | 2532 | * |
| 2455 | * Returns: | 2533 | * Returns: |
| 2456 | * Zero on success, errno on failure. | 2534 | * Zero on success, negative errno on failure. |
| 2457 | */ | 2535 | */ |
| 2458 | int drm_mode_set_config_internal(struct drm_mode_set *set) | 2536 | int drm_mode_set_config_internal(struct drm_mode_set *set) |
| 2459 | { | 2537 | { |
| @@ -2546,7 +2624,7 @@ EXPORT_SYMBOL(drm_crtc_check_viewport); | |||
| 2546 | * Called by the user via ioctl. | 2624 | * Called by the user via ioctl. |
| 2547 | * | 2625 | * |
| 2548 | * Returns: | 2626 | * Returns: |
| 2549 | * Zero on success, errno on failure. | 2627 | * Zero on success, negative errno on failure. |
| 2550 | */ | 2628 | */ |
| 2551 | int drm_mode_setcrtc(struct drm_device *dev, void *data, | 2629 | int drm_mode_setcrtc(struct drm_device *dev, void *data, |
| 2552 | struct drm_file *file_priv) | 2630 | struct drm_file *file_priv) |
| @@ -2709,7 +2787,7 @@ out: | |||
| 2709 | * userspace wants to make use of these capabilities. | 2787 | * userspace wants to make use of these capabilities. |
| 2710 | * | 2788 | * |
| 2711 | * Returns: | 2789 | * Returns: |
| 2712 | * Zero on success, errno on failure. | 2790 | * Zero on success, negative errno on failure. |
| 2713 | */ | 2791 | */ |
| 2714 | static int drm_mode_cursor_universal(struct drm_crtc *crtc, | 2792 | static int drm_mode_cursor_universal(struct drm_crtc *crtc, |
| 2715 | struct drm_mode_cursor2 *req, | 2793 | struct drm_mode_cursor2 *req, |
| @@ -2810,7 +2888,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, | |||
| 2810 | * If this crtc has a universal cursor plane, call that plane's update | 2888 | * If this crtc has a universal cursor plane, call that plane's update |
| 2811 | * handler rather than using legacy cursor handlers. | 2889 | * handler rather than using legacy cursor handlers. |
| 2812 | */ | 2890 | */ |
| 2813 | drm_modeset_lock_crtc(crtc); | 2891 | drm_modeset_lock_crtc(crtc, crtc->cursor); |
| 2814 | if (crtc->cursor) { | 2892 | if (crtc->cursor) { |
| 2815 | ret = drm_mode_cursor_universal(crtc, req, file_priv); | 2893 | ret = drm_mode_cursor_universal(crtc, req, file_priv); |
| 2816 | goto out; | 2894 | goto out; |
| @@ -2857,7 +2935,7 @@ out: | |||
| 2857 | * Called by the user via ioctl. | 2935 | * Called by the user via ioctl. |
| 2858 | * | 2936 | * |
| 2859 | * Returns: | 2937 | * Returns: |
| 2860 | * Zero on success, errno on failure. | 2938 | * Zero on success, negative errno on failure. |
| 2861 | */ | 2939 | */ |
| 2862 | int drm_mode_cursor_ioctl(struct drm_device *dev, | 2940 | int drm_mode_cursor_ioctl(struct drm_device *dev, |
| 2863 | void *data, struct drm_file *file_priv) | 2941 | void *data, struct drm_file *file_priv) |
| @@ -2884,7 +2962,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, | |||
| 2884 | * Called by the user via ioctl. | 2962 | * Called by the user via ioctl. |
| 2885 | * | 2963 | * |
| 2886 | * Returns: | 2964 | * Returns: |
| 2887 | * Zero on success, errno on failure. | 2965 | * Zero on success, negative errno on failure. |
| 2888 | */ | 2966 | */ |
| 2889 | int drm_mode_cursor2_ioctl(struct drm_device *dev, | 2967 | int drm_mode_cursor2_ioctl(struct drm_device *dev, |
| 2890 | void *data, struct drm_file *file_priv) | 2968 | void *data, struct drm_file *file_priv) |
| @@ -2943,23 +3021,21 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format); | |||
| 2943 | * @file_priv: drm file for the ioctl call | 3021 | * @file_priv: drm file for the ioctl call |
| 2944 | * | 3022 | * |
| 2945 | * Add a new FB to the specified CRTC, given a user request. This is the | 3023 | * Add a new FB to the specified CRTC, given a user request. This is the |
| 2946 | * original addfb ioclt which only supported RGB formats. | 3024 | * original addfb ioctl which only supported RGB formats. |
| 2947 | * | 3025 | * |
| 2948 | * Called by the user via ioctl. | 3026 | * Called by the user via ioctl. |
| 2949 | * | 3027 | * |
| 2950 | * Returns: | 3028 | * Returns: |
| 2951 | * Zero on success, errno on failure. | 3029 | * Zero on success, negative errno on failure. |
| 2952 | */ | 3030 | */ |
| 2953 | int drm_mode_addfb(struct drm_device *dev, | 3031 | int drm_mode_addfb(struct drm_device *dev, |
| 2954 | void *data, struct drm_file *file_priv) | 3032 | void *data, struct drm_file *file_priv) |
| 2955 | { | 3033 | { |
| 2956 | struct drm_mode_fb_cmd *or = data; | 3034 | struct drm_mode_fb_cmd *or = data; |
| 2957 | struct drm_mode_fb_cmd2 r = {}; | 3035 | struct drm_mode_fb_cmd2 r = {}; |
| 2958 | struct drm_mode_config *config = &dev->mode_config; | 3036 | int ret; |
| 2959 | struct drm_framebuffer *fb; | ||
| 2960 | int ret = 0; | ||
| 2961 | 3037 | ||
| 2962 | /* Use new struct with format internally */ | 3038 | /* convert to new format and call new ioctl */ |
| 2963 | r.fb_id = or->fb_id; | 3039 | r.fb_id = or->fb_id; |
| 2964 | r.width = or->width; | 3040 | r.width = or->width; |
| 2965 | r.height = or->height; | 3041 | r.height = or->height; |
| @@ -2967,28 +3043,13 @@ int drm_mode_addfb(struct drm_device *dev, | |||
| 2967 | r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); | 3043 | r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); |
| 2968 | r.handles[0] = or->handle; | 3044 | r.handles[0] = or->handle; |
| 2969 | 3045 | ||
| 2970 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3046 | ret = drm_mode_addfb2(dev, &r, file_priv); |
| 2971 | return -EINVAL; | 3047 | if (ret) |
| 2972 | 3048 | return ret; | |
| 2973 | if ((config->min_width > r.width) || (r.width > config->max_width)) | ||
| 2974 | return -EINVAL; | ||
| 2975 | |||
| 2976 | if ((config->min_height > r.height) || (r.height > config->max_height)) | ||
| 2977 | return -EINVAL; | ||
| 2978 | 3049 | ||
| 2979 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); | 3050 | or->fb_id = r.fb_id; |
| 2980 | if (IS_ERR(fb)) { | ||
| 2981 | DRM_DEBUG_KMS("could not create framebuffer\n"); | ||
| 2982 | return PTR_ERR(fb); | ||
| 2983 | } | ||
| 2984 | 3051 | ||
| 2985 | mutex_lock(&file_priv->fbs_lock); | 3052 | return 0; |
| 2986 | or->fb_id = fb->base.id; | ||
| 2987 | list_add(&fb->filp_head, &file_priv->fbs); | ||
| 2988 | DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); | ||
| 2989 | mutex_unlock(&file_priv->fbs_lock); | ||
| 2990 | |||
| 2991 | return ret; | ||
| 2992 | } | 3053 | } |
| 2993 | 3054 | ||
| 2994 | static int format_check(const struct drm_mode_fb_cmd2 *r) | 3055 | static int format_check(const struct drm_mode_fb_cmd2 *r) |
| @@ -3080,7 +3141,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | |||
| 3080 | num_planes = drm_format_num_planes(r->pixel_format); | 3141 | num_planes = drm_format_num_planes(r->pixel_format); |
| 3081 | 3142 | ||
| 3082 | if (r->width == 0 || r->width % hsub) { | 3143 | if (r->width == 0 || r->width % hsub) { |
| 3083 | DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height); | 3144 | DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); |
| 3084 | return -EINVAL; | 3145 | return -EINVAL; |
| 3085 | } | 3146 | } |
| 3086 | 3147 | ||
| @@ -3170,7 +3231,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, | |||
| 3170 | * Called by the user via ioctl. | 3231 | * Called by the user via ioctl. |
| 3171 | * | 3232 | * |
| 3172 | * Returns: | 3233 | * Returns: |
| 3173 | * Zero on success, errno on failure. | 3234 | * Zero on success, negative errno on failure. |
| 3174 | */ | 3235 | */ |
| 3175 | int drm_mode_addfb2(struct drm_device *dev, | 3236 | int drm_mode_addfb2(struct drm_device *dev, |
| 3176 | void *data, struct drm_file *file_priv) | 3237 | void *data, struct drm_file *file_priv) |
| @@ -3198,7 +3259,7 @@ int drm_mode_addfb2(struct drm_device *dev, | |||
| 3198 | * Called by the user via ioctl. | 3259 | * Called by the user via ioctl. |
| 3199 | * | 3260 | * |
| 3200 | * Returns: | 3261 | * Returns: |
| 3201 | * Zero on success, errno on failure. | 3262 | * Zero on success, negative errno on failure. |
| 3202 | */ | 3263 | */ |
| 3203 | int drm_mode_rmfb(struct drm_device *dev, | 3264 | int drm_mode_rmfb(struct drm_device *dev, |
| 3204 | void *data, struct drm_file *file_priv) | 3265 | void *data, struct drm_file *file_priv) |
| @@ -3252,7 +3313,7 @@ fail_lookup: | |||
| 3252 | * Called by the user via ioctl. | 3313 | * Called by the user via ioctl. |
| 3253 | * | 3314 | * |
| 3254 | * Returns: | 3315 | * Returns: |
| 3255 | * Zero on success, errno on failure. | 3316 | * Zero on success, negative errno on failure. |
| 3256 | */ | 3317 | */ |
| 3257 | int drm_mode_getfb(struct drm_device *dev, | 3318 | int drm_mode_getfb(struct drm_device *dev, |
| 3258 | void *data, struct drm_file *file_priv) | 3319 | void *data, struct drm_file *file_priv) |
| @@ -3313,7 +3374,7 @@ int drm_mode_getfb(struct drm_device *dev, | |||
| 3313 | * Called by the user via ioctl. | 3374 | * Called by the user via ioctl. |
| 3314 | * | 3375 | * |
| 3315 | * Returns: | 3376 | * Returns: |
| 3316 | * Zero on success, errno on failure. | 3377 | * Zero on success, negative errno on failure. |
| 3317 | */ | 3378 | */ |
| 3318 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | 3379 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, |
| 3319 | void *data, struct drm_file *file_priv) | 3380 | void *data, struct drm_file *file_priv) |
| @@ -3393,7 +3454,7 @@ out_err1: | |||
| 3393 | * Called by the user via ioctl. | 3454 | * Called by the user via ioctl. |
| 3394 | * | 3455 | * |
| 3395 | * Returns: | 3456 | * Returns: |
| 3396 | * Zero on success, errno on failure. | 3457 | * Zero on success, negative errno on failure. |
| 3397 | */ | 3458 | */ |
| 3398 | void drm_fb_release(struct drm_file *priv) | 3459 | void drm_fb_release(struct drm_file *priv) |
| 3399 | { | 3460 | { |
| @@ -3402,7 +3463,7 @@ void drm_fb_release(struct drm_file *priv) | |||
| 3402 | 3463 | ||
| 3403 | /* | 3464 | /* |
| 3404 | * When the file gets released that means no one else can access the fb | 3465 | * When the file gets released that means no one else can access the fb |
| 3405 | * list any more, so no need to grab fpriv->fbs_lock. And we need to to | 3466 | * list any more, so no need to grab fpriv->fbs_lock. And we need to |
| 3406 | * avoid upsetting lockdep since the universal cursor code adds a | 3467 | * avoid upsetting lockdep since the universal cursor code adds a |
| 3407 | * framebuffer while holding mutex locks. | 3468 | * framebuffer while holding mutex locks. |
| 3408 | * | 3469 | * |
| @@ -3435,6 +3496,10 @@ void drm_fb_release(struct drm_file *priv) | |||
| 3435 | * object with drm_object_attach_property. The returned property object must be | 3496 | * object with drm_object_attach_property. The returned property object must be |
| 3436 | * freed with drm_property_destroy. | 3497 | * freed with drm_property_destroy. |
| 3437 | * | 3498 | * |
| 3499 | * Note that the DRM core keeps a per-device list of properties and that, if | ||
| 3500 | * drm_mode_config_cleanup() is called, it will destroy all properties created | ||
| 3501 | * by the driver. | ||
| 3502 | * | ||
| 3438 | * Returns: | 3503 | * Returns: |
| 3439 | * A pointer to the newly created property on success, NULL on failure. | 3504 | * A pointer to the newly created property on success, NULL on failure. |
| 3440 | */ | 3505 | */ |
| @@ -3462,7 +3527,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, | |||
| 3462 | 3527 | ||
| 3463 | property->flags = flags; | 3528 | property->flags = flags; |
| 3464 | property->num_values = num_values; | 3529 | property->num_values = num_values; |
| 3465 | INIT_LIST_HEAD(&property->enum_blob_list); | 3530 | INIT_LIST_HEAD(&property->enum_list); |
| 3466 | 3531 | ||
| 3467 | if (name) { | 3532 | if (name) { |
| 3468 | strncpy(property->name, name, DRM_PROP_NAME_LEN); | 3533 | strncpy(property->name, name, DRM_PROP_NAME_LEN); |
| @@ -3611,7 +3676,7 @@ static struct drm_property *property_create_range(struct drm_device *dev, | |||
| 3611 | * object with drm_object_attach_property. The returned property object must be | 3676 | * object with drm_object_attach_property. The returned property object must be |
| 3612 | * freed with drm_property_destroy. | 3677 | * freed with drm_property_destroy. |
| 3613 | * | 3678 | * |
| 3614 | * Userspace is allowed to set any interger value in the (min, max) range | 3679 | * Userspace is allowed to set any integer value in the (min, max) range |
| 3615 | * inclusive. | 3680 | * inclusive. |
| 3616 | * | 3681 | * |
| 3617 | * Returns: | 3682 | * Returns: |
| @@ -3684,8 +3749,8 @@ int drm_property_add_enum(struct drm_property *property, int index, | |||
| 3684 | (value > 63)) | 3749 | (value > 63)) |
| 3685 | return -EINVAL; | 3750 | return -EINVAL; |
| 3686 | 3751 | ||
| 3687 | if (!list_empty(&property->enum_blob_list)) { | 3752 | if (!list_empty(&property->enum_list)) { |
| 3688 | list_for_each_entry(prop_enum, &property->enum_blob_list, head) { | 3753 | list_for_each_entry(prop_enum, &property->enum_list, head) { |
| 3689 | if (prop_enum->value == value) { | 3754 | if (prop_enum->value == value) { |
| 3690 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | 3755 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); |
| 3691 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | 3756 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; |
| @@ -3703,7 +3768,7 @@ int drm_property_add_enum(struct drm_property *property, int index, | |||
| 3703 | prop_enum->value = value; | 3768 | prop_enum->value = value; |
| 3704 | 3769 | ||
| 3705 | property->values[index] = value; | 3770 | property->values[index] = value; |
| 3706 | list_add_tail(&prop_enum->head, &property->enum_blob_list); | 3771 | list_add_tail(&prop_enum->head, &property->enum_list); |
| 3707 | return 0; | 3772 | return 0; |
| 3708 | } | 3773 | } |
| 3709 | EXPORT_SYMBOL(drm_property_add_enum); | 3774 | EXPORT_SYMBOL(drm_property_add_enum); |
| @@ -3720,7 +3785,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) | |||
| 3720 | { | 3785 | { |
| 3721 | struct drm_property_enum *prop_enum, *pt; | 3786 | struct drm_property_enum *prop_enum, *pt; |
| 3722 | 3787 | ||
| 3723 | list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { | 3788 | list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { |
| 3724 | list_del(&prop_enum->head); | 3789 | list_del(&prop_enum->head); |
| 3725 | kfree(prop_enum); | 3790 | kfree(prop_enum); |
| 3726 | } | 3791 | } |
| @@ -3823,17 +3888,20 @@ int drm_object_property_get_value(struct drm_mode_object *obj, | |||
| 3823 | EXPORT_SYMBOL(drm_object_property_get_value); | 3888 | EXPORT_SYMBOL(drm_object_property_get_value); |
| 3824 | 3889 | ||
| 3825 | /** | 3890 | /** |
| 3826 | * drm_mode_getproperty_ioctl - get the current value of a connector's property | 3891 | * drm_mode_getproperty_ioctl - get the property metadata |
| 3827 | * @dev: DRM device | 3892 | * @dev: DRM device |
| 3828 | * @data: ioctl data | 3893 | * @data: ioctl data |
| 3829 | * @file_priv: DRM file info | 3894 | * @file_priv: DRM file info |
| 3830 | * | 3895 | * |
| 3831 | * This function retrieves the current value for an connectors's property. | 3896 | * This function retrieves the metadata for a given property, like the different |
| 3897 | * possible values for an enum property or the limits for a range property. | ||
| 3898 | * | ||
| 3899 | * Blob properties are special | ||
| 3832 | * | 3900 | * |
| 3833 | * Called by the user via ioctl. | 3901 | * Called by the user via ioctl. |
| 3834 | * | 3902 | * |
| 3835 | * Returns: | 3903 | * Returns: |
| 3836 | * Zero on success, errno on failure. | 3904 | * Zero on success, negative errno on failure. |
| 3837 | */ | 3905 | */ |
| 3838 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | 3906 | int drm_mode_getproperty_ioctl(struct drm_device *dev, |
| 3839 | void *data, struct drm_file *file_priv) | 3907 | void *data, struct drm_file *file_priv) |
| @@ -3841,16 +3909,12 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | |||
| 3841 | struct drm_mode_get_property *out_resp = data; | 3909 | struct drm_mode_get_property *out_resp = data; |
| 3842 | struct drm_property *property; | 3910 | struct drm_property *property; |
| 3843 | int enum_count = 0; | 3911 | int enum_count = 0; |
| 3844 | int blob_count = 0; | ||
| 3845 | int value_count = 0; | 3912 | int value_count = 0; |
| 3846 | int ret = 0, i; | 3913 | int ret = 0, i; |
| 3847 | int copied; | 3914 | int copied; |
| 3848 | struct drm_property_enum *prop_enum; | 3915 | struct drm_property_enum *prop_enum; |
| 3849 | struct drm_mode_property_enum __user *enum_ptr; | 3916 | struct drm_mode_property_enum __user *enum_ptr; |
| 3850 | struct drm_property_blob *prop_blob; | ||
| 3851 | uint32_t __user *blob_id_ptr; | ||
| 3852 | uint64_t __user *values_ptr; | 3917 | uint64_t __user *values_ptr; |
| 3853 | uint32_t __user *blob_length_ptr; | ||
| 3854 | 3918 | ||
| 3855 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3919 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 3856 | return -EINVAL; | 3920 | return -EINVAL; |
| @@ -3864,11 +3928,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | |||
| 3864 | 3928 | ||
| 3865 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || | 3929 | if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || |
| 3866 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | 3930 | drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { |
| 3867 | list_for_each_entry(prop_enum, &property->enum_blob_list, head) | 3931 | list_for_each_entry(prop_enum, &property->enum_list, head) |
| 3868 | enum_count++; | 3932 | enum_count++; |
| 3869 | } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { | ||
| 3870 | list_for_each_entry(prop_blob, &property->enum_blob_list, head) | ||
| 3871 | blob_count++; | ||
| 3872 | } | 3933 | } |
| 3873 | 3934 | ||
| 3874 | value_count = property->num_values; | 3935 | value_count = property->num_values; |
| @@ -3893,7 +3954,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | |||
| 3893 | if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { | 3954 | if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { |
| 3894 | copied = 0; | 3955 | copied = 0; |
| 3895 | enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; | 3956 | enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; |
| 3896 | list_for_each_entry(prop_enum, &property->enum_blob_list, head) { | 3957 | list_for_each_entry(prop_enum, &property->enum_list, head) { |
| 3897 | 3958 | ||
| 3898 | if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { | 3959 | if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { |
| 3899 | ret = -EFAULT; | 3960 | ret = -EFAULT; |
| @@ -3911,35 +3972,24 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | |||
| 3911 | out_resp->count_enum_blobs = enum_count; | 3972 | out_resp->count_enum_blobs = enum_count; |
| 3912 | } | 3973 | } |
| 3913 | 3974 | ||
| 3914 | if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { | 3975 | /* |
| 3915 | if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { | 3976 | * NOTE: The idea seems to have been to use this to read all the blob |
| 3916 | copied = 0; | 3977 | * property values. But nothing ever added them to the corresponding |
| 3917 | blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr; | 3978 | * list, userspace always used the special-purpose get_blob ioctl to |
| 3918 | blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr; | 3979 | * read the value for a blob property. It also doesn't make a lot of |
| 3919 | 3980 | * sense to return values here when everything else is just metadata for | |
| 3920 | list_for_each_entry(prop_blob, &property->enum_blob_list, head) { | 3981 | * the property itself. |
| 3921 | if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { | 3982 | */ |
| 3922 | ret = -EFAULT; | 3983 | if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) |
| 3923 | goto done; | 3984 | out_resp->count_enum_blobs = 0; |
| 3924 | } | ||
| 3925 | |||
| 3926 | if (put_user(prop_blob->length, blob_length_ptr + copied)) { | ||
| 3927 | ret = -EFAULT; | ||
| 3928 | goto done; | ||
| 3929 | } | ||
| 3930 | |||
| 3931 | copied++; | ||
| 3932 | } | ||
| 3933 | } | ||
| 3934 | out_resp->count_enum_blobs = blob_count; | ||
| 3935 | } | ||
| 3936 | done: | 3985 | done: |
| 3937 | drm_modeset_unlock_all(dev); | 3986 | drm_modeset_unlock_all(dev); |
| 3938 | return ret; | 3987 | return ret; |
| 3939 | } | 3988 | } |
| 3940 | 3989 | ||
| 3941 | static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, | 3990 | static struct drm_property_blob * |
| 3942 | void *data) | 3991 | drm_property_create_blob(struct drm_device *dev, size_t length, |
| 3992 | const void *data) | ||
| 3943 | { | 3993 | { |
| 3944 | struct drm_property_blob *blob; | 3994 | struct drm_property_blob *blob; |
| 3945 | int ret; | 3995 | int ret; |
| @@ -3985,7 +4035,7 @@ static void drm_property_destroy_blob(struct drm_device *dev, | |||
| 3985 | * Called by the user via ioctl. | 4035 | * Called by the user via ioctl. |
| 3986 | * | 4036 | * |
| 3987 | * Returns: | 4037 | * Returns: |
| 3988 | * Zero on success, errno on failure. | 4038 | * Zero on success, negative errno on failure. |
| 3989 | */ | 4039 | */ |
| 3990 | int drm_mode_getblob_ioctl(struct drm_device *dev, | 4040 | int drm_mode_getblob_ioctl(struct drm_device *dev, |
| 3991 | void *data, struct drm_file *file_priv) | 4041 | void *data, struct drm_file *file_priv) |
| @@ -4019,12 +4069,25 @@ done: | |||
| 4019 | return ret; | 4069 | return ret; |
| 4020 | } | 4070 | } |
| 4021 | 4071 | ||
| 4072 | /** | ||
| 4073 | * drm_mode_connector_set_path_property - set tile property on connector | ||
| 4074 | * @connector: connector to set property on. | ||
| 4075 | * @path: path to use for property. | ||
| 4076 | * | ||
| 4077 | * This creates a property to expose to userspace to specify a | ||
| 4078 | * connector path. This is mainly used for DisplayPort MST where | ||
| 4079 | * connectors have a topology and we want to allow userspace to give | ||
| 4080 | * them more meaningful names. | ||
| 4081 | * | ||
| 4082 | * Returns: | ||
| 4083 | * Zero on success, negative errno on failure. | ||
| 4084 | */ | ||
| 4022 | int drm_mode_connector_set_path_property(struct drm_connector *connector, | 4085 | int drm_mode_connector_set_path_property(struct drm_connector *connector, |
| 4023 | char *path) | 4086 | const char *path) |
| 4024 | { | 4087 | { |
| 4025 | struct drm_device *dev = connector->dev; | 4088 | struct drm_device *dev = connector->dev; |
| 4026 | int ret, size; | 4089 | size_t size = strlen(path) + 1; |
| 4027 | size = strlen(path) + 1; | 4090 | int ret; |
| 4028 | 4091 | ||
| 4029 | connector->path_blob_ptr = drm_property_create_blob(connector->dev, | 4092 | connector->path_blob_ptr = drm_property_create_blob(connector->dev, |
| 4030 | size, path); | 4093 | size, path); |
| @@ -4039,6 +4102,52 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector, | |||
| 4039 | EXPORT_SYMBOL(drm_mode_connector_set_path_property); | 4102 | EXPORT_SYMBOL(drm_mode_connector_set_path_property); |
| 4040 | 4103 | ||
| 4041 | /** | 4104 | /** |
| 4105 | * drm_mode_connector_set_tile_property - set tile property on connector | ||
| 4106 | * @connector: connector to set property on. | ||
| 4107 | * | ||
| 4108 | * This looks up the tile information for a connector, and creates a | ||
| 4109 | * property for userspace to parse if it exists. The property is of | ||
| 4110 | * the form of 8 integers using ':' as a separator. | ||
| 4111 | * | ||
| 4112 | * Returns: | ||
| 4113 | * Zero on success, errno on failure. | ||
| 4114 | */ | ||
| 4115 | int drm_mode_connector_set_tile_property(struct drm_connector *connector) | ||
| 4116 | { | ||
| 4117 | struct drm_device *dev = connector->dev; | ||
| 4118 | int ret, size; | ||
| 4119 | char tile[256]; | ||
| 4120 | |||
| 4121 | if (connector->tile_blob_ptr) | ||
| 4122 | drm_property_destroy_blob(dev, connector->tile_blob_ptr); | ||
| 4123 | |||
| 4124 | if (!connector->has_tile) { | ||
| 4125 | connector->tile_blob_ptr = NULL; | ||
| 4126 | ret = drm_object_property_set_value(&connector->base, | ||
| 4127 | dev->mode_config.tile_property, 0); | ||
| 4128 | return ret; | ||
| 4129 | } | ||
| 4130 | |||
| 4131 | snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", | ||
| 4132 | connector->tile_group->id, connector->tile_is_single_monitor, | ||
| 4133 | connector->num_h_tile, connector->num_v_tile, | ||
| 4134 | connector->tile_h_loc, connector->tile_v_loc, | ||
| 4135 | connector->tile_h_size, connector->tile_v_size); | ||
| 4136 | size = strlen(tile) + 1; | ||
| 4137 | |||
| 4138 | connector->tile_blob_ptr = drm_property_create_blob(connector->dev, | ||
| 4139 | size, tile); | ||
| 4140 | if (!connector->tile_blob_ptr) | ||
| 4141 | return -EINVAL; | ||
| 4142 | |||
| 4143 | ret = drm_object_property_set_value(&connector->base, | ||
| 4144 | dev->mode_config.tile_property, | ||
| 4145 | connector->tile_blob_ptr->base.id); | ||
| 4146 | return ret; | ||
| 4147 | } | ||
| 4148 | EXPORT_SYMBOL(drm_mode_connector_set_tile_property); | ||
| 4149 | |||
| 4150 | /** | ||
| 4042 | * drm_mode_connector_update_edid_property - update the edid property of a connector | 4151 | * drm_mode_connector_update_edid_property - update the edid property of a connector |
| 4043 | * @connector: drm connector | 4152 | * @connector: drm connector |
| 4044 | * @edid: new value of the edid property | 4153 | * @edid: new value of the edid property |
| @@ -4047,13 +4156,14 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property); | |||
| 4047 | * connector's edid property. | 4156 | * connector's edid property. |
| 4048 | * | 4157 | * |
| 4049 | * Returns: | 4158 | * Returns: |
| 4050 | * Zero on success, errno on failure. | 4159 | * Zero on success, negative errno on failure. |
| 4051 | */ | 4160 | */ |
| 4052 | int drm_mode_connector_update_edid_property(struct drm_connector *connector, | 4161 | int drm_mode_connector_update_edid_property(struct drm_connector *connector, |
| 4053 | struct edid *edid) | 4162 | const struct edid *edid) |
| 4054 | { | 4163 | { |
| 4055 | struct drm_device *dev = connector->dev; | 4164 | struct drm_device *dev = connector->dev; |
| 4056 | int ret, size; | 4165 | size_t size; |
| 4166 | int ret; | ||
| 4057 | 4167 | ||
| 4058 | /* ignore requests to set edid when overridden */ | 4168 | /* ignore requests to set edid when overridden */ |
| 4059 | if (connector->override_edid) | 4169 | if (connector->override_edid) |
| @@ -4143,7 +4253,7 @@ static bool drm_property_change_is_valid(struct drm_property *property, | |||
| 4143 | * Called by the user via ioctl. | 4253 | * Called by the user via ioctl. |
| 4144 | * | 4254 | * |
| 4145 | * Returns: | 4255 | * Returns: |
| 4146 | * Zero on success, errno on failure. | 4256 | * Zero on success, negative errno on failure. |
| 4147 | */ | 4257 | */ |
| 4148 | int drm_mode_connector_property_set_ioctl(struct drm_device *dev, | 4258 | int drm_mode_connector_property_set_ioctl(struct drm_device *dev, |
| 4149 | void *data, struct drm_file *file_priv) | 4259 | void *data, struct drm_file *file_priv) |
| @@ -4226,7 +4336,7 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane, | |||
| 4226 | EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); | 4336 | EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); |
| 4227 | 4337 | ||
| 4228 | /** | 4338 | /** |
| 4229 | * drm_mode_getproperty_ioctl - get the current value of a object's property | 4339 | * drm_mode_obj_get_properties_ioctl - get the current value of a object's property |
| 4230 | * @dev: DRM device | 4340 | * @dev: DRM device |
| 4231 | * @data: ioctl data | 4341 | * @data: ioctl data |
| 4232 | * @file_priv: DRM file info | 4342 | * @file_priv: DRM file info |
| @@ -4238,7 +4348,7 @@ EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); | |||
| 4238 | * Called by the user via ioctl. | 4348 | * Called by the user via ioctl. |
| 4239 | * | 4349 | * |
| 4240 | * Returns: | 4350 | * Returns: |
| 4241 | * Zero on success, errno on failure. | 4351 | * Zero on success, negative errno on failure. |
| 4242 | */ | 4352 | */ |
| 4243 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | 4353 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, |
| 4244 | struct drm_file *file_priv) | 4354 | struct drm_file *file_priv) |
| @@ -4310,7 +4420,7 @@ out: | |||
| 4310 | * Called by the user via ioctl. | 4420 | * Called by the user via ioctl. |
| 4311 | * | 4421 | * |
| 4312 | * Returns: | 4422 | * Returns: |
| 4313 | * Zero on success, errno on failure. | 4423 | * Zero on success, negative errno on failure. |
| 4314 | */ | 4424 | */ |
| 4315 | int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | 4425 | int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, |
| 4316 | struct drm_file *file_priv) | 4426 | struct drm_file *file_priv) |
| @@ -4382,7 +4492,7 @@ out: | |||
| 4382 | * possible_clones and possible_crtcs bitmasks. | 4492 | * possible_clones and possible_crtcs bitmasks. |
| 4383 | * | 4493 | * |
| 4384 | * Returns: | 4494 | * Returns: |
| 4385 | * Zero on success, errno on failure. | 4495 | * Zero on success, negative errno on failure. |
| 4386 | */ | 4496 | */ |
| 4387 | int drm_mode_connector_attach_encoder(struct drm_connector *connector, | 4497 | int drm_mode_connector_attach_encoder(struct drm_connector *connector, |
| 4388 | struct drm_encoder *encoder) | 4498 | struct drm_encoder *encoder) |
| @@ -4409,7 +4519,7 @@ EXPORT_SYMBOL(drm_mode_connector_attach_encoder); | |||
| 4409 | * fixed gamma table size. | 4519 | * fixed gamma table size. |
| 4410 | * | 4520 | * |
| 4411 | * Returns: | 4521 | * Returns: |
| 4412 | * Zero on success, errno on failure. | 4522 | * Zero on success, negative errno on failure. |
| 4413 | */ | 4523 | */ |
| 4414 | int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | 4524 | int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, |
| 4415 | int gamma_size) | 4525 | int gamma_size) |
| @@ -4438,7 +4548,7 @@ EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); | |||
| 4438 | * Called by the user via ioctl. | 4548 | * Called by the user via ioctl. |
| 4439 | * | 4549 | * |
| 4440 | * Returns: | 4550 | * Returns: |
| 4441 | * Zero on success, errno on failure. | 4551 | * Zero on success, negative errno on failure. |
| 4442 | */ | 4552 | */ |
| 4443 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | 4553 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, |
| 4444 | void *data, struct drm_file *file_priv) | 4554 | void *data, struct drm_file *file_priv) |
| @@ -4510,7 +4620,7 @@ out: | |||
| 4510 | * Called by the user via ioctl. | 4620 | * Called by the user via ioctl. |
| 4511 | * | 4621 | * |
| 4512 | * Returns: | 4622 | * Returns: |
| 4513 | * Zero on success, errno on failure. | 4623 | * Zero on success, negative errno on failure. |
| 4514 | */ | 4624 | */ |
| 4515 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | 4625 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, |
| 4516 | void *data, struct drm_file *file_priv) | 4626 | void *data, struct drm_file *file_priv) |
| @@ -4576,7 +4686,7 @@ out: | |||
| 4576 | * Called by the user via ioctl. | 4686 | * Called by the user via ioctl. |
| 4577 | * | 4687 | * |
| 4578 | * Returns: | 4688 | * Returns: |
| 4579 | * Zero on success, errno on failure. | 4689 | * Zero on success, negative errno on failure. |
| 4580 | */ | 4690 | */ |
| 4581 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | 4691 | int drm_mode_page_flip_ioctl(struct drm_device *dev, |
| 4582 | void *data, struct drm_file *file_priv) | 4692 | void *data, struct drm_file *file_priv) |
| @@ -4599,7 +4709,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
| 4599 | if (!crtc) | 4709 | if (!crtc) |
| 4600 | return -ENOENT; | 4710 | return -ENOENT; |
| 4601 | 4711 | ||
| 4602 | drm_modeset_lock_crtc(crtc); | 4712 | drm_modeset_lock_crtc(crtc, crtc->primary); |
| 4603 | if (crtc->primary->fb == NULL) { | 4713 | if (crtc->primary->fb == NULL) { |
| 4604 | /* The framebuffer is currently unbound, presumably | 4714 | /* The framebuffer is currently unbound, presumably |
| 4605 | * due to a hotplug event, that userspace has not | 4715 | * due to a hotplug event, that userspace has not |
| @@ -4742,7 +4852,7 @@ EXPORT_SYMBOL(drm_mode_config_reset); | |||
| 4742 | * Called by the user via ioctl. | 4852 | * Called by the user via ioctl. |
| 4743 | * | 4853 | * |
| 4744 | * Returns: | 4854 | * Returns: |
| 4745 | * Zero on success, errno on failure. | 4855 | * Zero on success, negative errno on failure. |
| 4746 | */ | 4856 | */ |
| 4747 | int drm_mode_create_dumb_ioctl(struct drm_device *dev, | 4857 | int drm_mode_create_dumb_ioctl(struct drm_device *dev, |
| 4748 | void *data, struct drm_file *file_priv) | 4858 | void *data, struct drm_file *file_priv) |
| @@ -4769,6 +4879,16 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, | |||
| 4769 | if (PAGE_ALIGN(size) == 0) | 4879 | if (PAGE_ALIGN(size) == 0) |
| 4770 | return -EINVAL; | 4880 | return -EINVAL; |
| 4771 | 4881 | ||
| 4882 | /* | ||
| 4883 | * handle, pitch and size are output parameters. Zero them out to | ||
| 4884 | * prevent drivers from accidentally using uninitialized data. Since | ||
| 4885 | * not all existing userspace is clearing these fields properly we | ||
| 4886 | * cannot reject IOCTL with garbage in them. | ||
| 4887 | */ | ||
| 4888 | args->handle = 0; | ||
| 4889 | args->pitch = 0; | ||
| 4890 | args->size = 0; | ||
| 4891 | |||
| 4772 | return dev->driver->dumb_create(file_priv, dev, args); | 4892 | return dev->driver->dumb_create(file_priv, dev, args); |
| 4773 | } | 4893 | } |
| 4774 | 4894 | ||
| @@ -4784,7 +4904,7 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, | |||
| 4784 | * Called by the user via ioctl. | 4904 | * Called by the user via ioctl. |
| 4785 | * | 4905 | * |
| 4786 | * Returns: | 4906 | * Returns: |
| 4787 | * Zero on success, errno on failure. | 4907 | * Zero on success, negative errno on failure. |
| 4788 | */ | 4908 | */ |
| 4789 | int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, | 4909 | int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, |
| 4790 | void *data, struct drm_file *file_priv) | 4910 | void *data, struct drm_file *file_priv) |
| @@ -4811,7 +4931,7 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, | |||
| 4811 | * Called by the user via ioctl. | 4931 | * Called by the user via ioctl. |
| 4812 | * | 4932 | * |
| 4813 | * Returns: | 4933 | * Returns: |
| 4814 | * Zero on success, errno on failure. | 4934 | * Zero on success, negative errno on failure. |
| 4815 | */ | 4935 | */ |
| 4816 | int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, | 4936 | int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, |
| 4817 | void *data, struct drm_file *file_priv) | 4937 | void *data, struct drm_file *file_priv) |
| @@ -5097,6 +5217,7 @@ void drm_mode_config_init(struct drm_device *dev) | |||
| 5097 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); | 5217 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); |
| 5098 | INIT_LIST_HEAD(&dev->mode_config.plane_list); | 5218 | INIT_LIST_HEAD(&dev->mode_config.plane_list); |
| 5099 | idr_init(&dev->mode_config.crtc_idr); | 5219 | idr_init(&dev->mode_config.crtc_idr); |
| 5220 | idr_init(&dev->mode_config.tile_idr); | ||
| 5100 | 5221 | ||
| 5101 | drm_modeset_lock_all(dev); | 5222 | drm_modeset_lock_all(dev); |
| 5102 | drm_mode_create_standard_connector_properties(dev); | 5223 | drm_mode_create_standard_connector_properties(dev); |
| @@ -5184,6 +5305,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
| 5184 | crtc->funcs->destroy(crtc); | 5305 | crtc->funcs->destroy(crtc); |
| 5185 | } | 5306 | } |
| 5186 | 5307 | ||
| 5308 | idr_destroy(&dev->mode_config.tile_idr); | ||
| 5187 | idr_destroy(&dev->mode_config.crtc_idr); | 5309 | idr_destroy(&dev->mode_config.crtc_idr); |
| 5188 | drm_modeset_lock_fini(&dev->mode_config.connection_mutex); | 5310 | drm_modeset_lock_fini(&dev->mode_config.connection_mutex); |
| 5189 | } | 5311 | } |
| @@ -5206,3 +5328,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, | |||
| 5206 | supported_rotations); | 5328 | supported_rotations); |
| 5207 | } | 5329 | } |
| 5208 | EXPORT_SYMBOL(drm_mode_create_rotation_property); | 5330 | EXPORT_SYMBOL(drm_mode_create_rotation_property); |
| 5331 | |||
| 5332 | /** | ||
| 5333 | * DOC: Tile group | ||
| 5334 | * | ||
| 5335 | * Tile groups are used to represent tiled monitors with a unique | ||
| 5336 | * integer identifier. Tiled monitors using DisplayID v1.3 have | ||
| 5337 | * a unique 8-byte handle, we store this in a tile group, so we | ||
| 5338 | * have a common identifier for all tiles in a monitor group. | ||
| 5339 | */ | ||
| 5340 | static void drm_tile_group_free(struct kref *kref) | ||
| 5341 | { | ||
| 5342 | struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); | ||
| 5343 | struct drm_device *dev = tg->dev; | ||
| 5344 | mutex_lock(&dev->mode_config.idr_mutex); | ||
| 5345 | idr_remove(&dev->mode_config.tile_idr, tg->id); | ||
| 5346 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
| 5347 | kfree(tg); | ||
| 5348 | } | ||
| 5349 | |||
| 5350 | /** | ||
| 5351 | * drm_mode_put_tile_group - drop a reference to a tile group. | ||
| 5352 | * @dev: DRM device | ||
| 5353 | * @tg: tile group to drop reference to. | ||
| 5354 | * | ||
| 5355 | * drop reference to tile group and free if 0. | ||
| 5356 | */ | ||
| 5357 | void drm_mode_put_tile_group(struct drm_device *dev, | ||
| 5358 | struct drm_tile_group *tg) | ||
| 5359 | { | ||
| 5360 | kref_put(&tg->refcount, drm_tile_group_free); | ||
| 5361 | } | ||
| 5362 | |||
| 5363 | /** | ||
| 5364 | * drm_mode_get_tile_group - get a reference to an existing tile group | ||
| 5365 | * @dev: DRM device | ||
| 5366 | * @topology: 8-bytes unique per monitor. | ||
| 5367 | * | ||
| 5368 | * Use the unique bytes to get a reference to an existing tile group. | ||
| 5369 | * | ||
| 5370 | * RETURNS: | ||
| 5371 | * tile group or NULL if not found. | ||
| 5372 | */ | ||
| 5373 | struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, | ||
| 5374 | char topology[8]) | ||
| 5375 | { | ||
| 5376 | struct drm_tile_group *tg; | ||
| 5377 | int id; | ||
| 5378 | mutex_lock(&dev->mode_config.idr_mutex); | ||
| 5379 | idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { | ||
| 5380 | if (!memcmp(tg->group_data, topology, 8)) { | ||
| 5381 | if (!kref_get_unless_zero(&tg->refcount)) | ||
| 5382 | tg = NULL; | ||
| 5383 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
| 5384 | return tg; | ||
| 5385 | } | ||
| 5386 | } | ||
| 5387 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
| 5388 | return NULL; | ||
| 5389 | } | ||
| 5390 | |||
| 5391 | /** | ||
| 5392 | * drm_mode_create_tile_group - create a tile group from a displayid description | ||
| 5393 | * @dev: DRM device | ||
| 5394 | * @topology: 8-bytes unique per monitor. | ||
| 5395 | * | ||
| 5396 | * Create a tile group for the unique monitor, and get a unique | ||
| 5397 | * identifier for the tile group. | ||
| 5398 | * | ||
| 5399 | * RETURNS: | ||
| 5400 | * new tile group or error. | ||
| 5401 | */ | ||
| 5402 | struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, | ||
| 5403 | char topology[8]) | ||
| 5404 | { | ||
| 5405 | struct drm_tile_group *tg; | ||
| 5406 | int ret; | ||
| 5407 | |||
| 5408 | tg = kzalloc(sizeof(*tg), GFP_KERNEL); | ||
| 5409 | if (!tg) | ||
| 5410 | return ERR_PTR(-ENOMEM); | ||
| 5411 | |||
| 5412 | kref_init(&tg->refcount); | ||
| 5413 | memcpy(tg->group_data, topology, 8); | ||
| 5414 | tg->dev = dev; | ||
| 5415 | |||
| 5416 | mutex_lock(&dev->mode_config.idr_mutex); | ||
| 5417 | ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); | ||
| 5418 | if (ret >= 0) { | ||
| 5419 | tg->id = ret; | ||
| 5420 | } else { | ||
| 5421 | kfree(tg); | ||
| 5422 | tg = ERR_PTR(ret); | ||
| 5423 | } | ||
| 5424 | |||
| 5425 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
| 5426 | return tg; | ||
| 5427 | } | ||
