diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-15 18:52:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-15 18:52:01 -0500 |
commit | 988adfdffdd43cfd841df734664727993076d7cb (patch) | |
tree | 6794f7bba8f595500c2b7d33376ad6614adcfaf2 /drivers/gpu/drm/drm_crtc.c | |
parent | 26178ec11ef3c6c814bf16a0a2b9c2f7242e3c64 (diff) | |
parent | 4e0cd68115620bc3236ff4e58e4c073948629b41 (diff) |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"Highlights:
- AMD KFD driver merge
This is the AMD HSA interface for exposing a lowlevel interface for
GPGPU use. They have an open source userspace built on top of this
interface, and the code looks as good as it was going to get out of
tree.
- Initial atomic modesetting work
The need for an atomic modesetting interface to allow userspace to
try and send a complete set of modesetting state to the driver has
arisen, and been suffering from neglect this past year. No more,
the start of the common code and changes for msm driver to use it
are in this tree. Ongoing work to get the userspace ioctl finished
and the code clean will probably wait until next kernel.
- DisplayID 1.3 and tiled monitor exposed to userspace.
Tiled monitor property is now exposed for userspace to make use of.
- Rockchip drm driver merged.
- imx gpu driver moved out of staging
Other stuff:
- core:
panel - MIPI DSI + new panels.
expose suggested x/y properties for virtual GPUs
- i915:
Initial Skylake (SKL) support
gen3/4 reset work
start of dri1/ums removal
infoframe tracking
fixes for lots of things.
- nouveau:
tegra k1 voltage support
GM204 modesetting support
GT21x memory reclocking work
- radeon:
CI dpm fixes
GPUVM improvements
Initial DPM fan control
- rcar-du:
HDMI support added
removed some support for old boards
slave encoder driver for Analog Devices adv7511
- exynos:
Exynos4415 SoC support
- msm:
a4xx gpu support
atomic helper conversion
- tegra:
iommu support
universal plane support
ganged-mode DSI support
- sti:
HDMI i2c improvements
- vmwgfx:
some late fixes.
- qxl:
use suggested x/y properties"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (969 commits)
drm: sti: fix module compilation issue
drm/i915: save/restore GMBUS freq across suspend/resume on gen4
drm: sti: correctly cleanup CRTC and planes
drm: sti: add HQVDP plane
drm: sti: add cursor plane
drm: sti: enable auxiliary CRTC
drm: sti: fix delay in VTG programming
drm: sti: prepare sti_tvout to support auxiliary crtc
drm: sti: use drm_crtc_vblank_{on/off} instead of drm_vblank_{on/off}
drm: sti: fix hdmi avi infoframe
drm: sti: remove event lock while disabling vblank
drm: sti: simplify gdp code
drm: sti: clear all mixer control
drm: sti: remove gpio for HDMI hot plug detection
drm: sti: allow to change hdmi ddc i2c adapter
drm/doc: Document drm_add_modes_noedid() usage
drm/i915: Remove '& 0xffff' from the mask given to WA_REG()
drm/i915: Invert the mask and val arguments in wa_add() and WA_REG()
drm: Zero out DRM object memory upon cleanup
drm/i915/bdw: Fix the write setting up the WIZ hashing mode
...
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 | } | ||