diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 394 |
1 files changed, 227 insertions, 167 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 90e773019eac..e79c8d3700d8 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -40,106 +40,12 @@ | |||
40 | #include <drm/drm_modeset_lock.h> | 40 | #include <drm/drm_modeset_lock.h> |
41 | 41 | ||
42 | #include "drm_crtc_internal.h" | 42 | #include "drm_crtc_internal.h" |
43 | #include "drm_internal.h" | ||
43 | 44 | ||
44 | static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, | 45 | static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, |
45 | struct drm_mode_fb_cmd2 *r, | 46 | struct drm_mode_fb_cmd2 *r, |
46 | struct drm_file *file_priv); | 47 | struct drm_file *file_priv); |
47 | 48 | ||
48 | /** | ||
49 | * drm_modeset_lock_all - take all modeset locks | ||
50 | * @dev: drm device | ||
51 | * | ||
52 | * This function takes all modeset locks, suitable where a more fine-grained | ||
53 | * scheme isn't (yet) implemented. Locks must be dropped with | ||
54 | * drm_modeset_unlock_all. | ||
55 | */ | ||
56 | void drm_modeset_lock_all(struct drm_device *dev) | ||
57 | { | ||
58 | struct drm_mode_config *config = &dev->mode_config; | ||
59 | struct drm_modeset_acquire_ctx *ctx; | ||
60 | int ret; | ||
61 | |||
62 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
63 | if (WARN_ON(!ctx)) | ||
64 | return; | ||
65 | |||
66 | mutex_lock(&config->mutex); | ||
67 | |||
68 | drm_modeset_acquire_init(ctx, 0); | ||
69 | |||
70 | retry: | ||
71 | ret = drm_modeset_lock(&config->connection_mutex, ctx); | ||
72 | if (ret) | ||
73 | goto fail; | ||
74 | ret = drm_modeset_lock_all_crtcs(dev, ctx); | ||
75 | if (ret) | ||
76 | goto fail; | ||
77 | |||
78 | WARN_ON(config->acquire_ctx); | ||
79 | |||
80 | /* now we hold the locks, so now that it is safe, stash the | ||
81 | * ctx for drm_modeset_unlock_all(): | ||
82 | */ | ||
83 | config->acquire_ctx = ctx; | ||
84 | |||
85 | drm_warn_on_modeset_not_all_locked(dev); | ||
86 | |||
87 | return; | ||
88 | |||
89 | fail: | ||
90 | if (ret == -EDEADLK) { | ||
91 | drm_modeset_backoff(ctx); | ||
92 | goto retry; | ||
93 | } | ||
94 | } | ||
95 | EXPORT_SYMBOL(drm_modeset_lock_all); | ||
96 | |||
97 | /** | ||
98 | * drm_modeset_unlock_all - drop all modeset locks | ||
99 | * @dev: device | ||
100 | * | ||
101 | * This function drop all modeset locks taken by drm_modeset_lock_all. | ||
102 | */ | ||
103 | void drm_modeset_unlock_all(struct drm_device *dev) | ||
104 | { | ||
105 | struct drm_mode_config *config = &dev->mode_config; | ||
106 | struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; | ||
107 | |||
108 | if (WARN_ON(!ctx)) | ||
109 | return; | ||
110 | |||
111 | config->acquire_ctx = NULL; | ||
112 | drm_modeset_drop_locks(ctx); | ||
113 | drm_modeset_acquire_fini(ctx); | ||
114 | |||
115 | kfree(ctx); | ||
116 | |||
117 | mutex_unlock(&dev->mode_config.mutex); | ||
118 | } | ||
119 | EXPORT_SYMBOL(drm_modeset_unlock_all); | ||
120 | |||
121 | /** | ||
122 | * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked | ||
123 | * @dev: device | ||
124 | * | ||
125 | * Useful as a debug assert. | ||
126 | */ | ||
127 | void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) | ||
128 | { | ||
129 | struct drm_crtc *crtc; | ||
130 | |||
131 | /* Locking is currently fubar in the panic handler. */ | ||
132 | if (oops_in_progress) | ||
133 | return; | ||
134 | |||
135 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
136 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | ||
137 | |||
138 | WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); | ||
139 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
140 | } | ||
141 | EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); | ||
142 | |||
143 | /* Avoid boilerplate. I'm tired of typing. */ | 49 | /* Avoid boilerplate. I'm tired of typing. */ |
144 | #define DRM_ENUM_NAME_FN(fnname, list) \ | 50 | #define DRM_ENUM_NAME_FN(fnname, list) \ |
145 | const char *fnname(int val) \ | 51 | const char *fnname(int val) \ |
@@ -515,9 +421,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | |||
515 | if (ret) | 421 | if (ret) |
516 | goto out; | 422 | goto out; |
517 | 423 | ||
518 | /* Grab the idr reference. */ | ||
519 | drm_framebuffer_reference(fb); | ||
520 | |||
521 | dev->mode_config.num_fb++; | 424 | dev->mode_config.num_fb++; |
522 | list_add(&fb->head, &dev->mode_config.fb_list); | 425 | list_add(&fb->head, &dev->mode_config.fb_list); |
523 | out: | 426 | out: |
@@ -527,10 +430,34 @@ out: | |||
527 | } | 430 | } |
528 | EXPORT_SYMBOL(drm_framebuffer_init); | 431 | EXPORT_SYMBOL(drm_framebuffer_init); |
529 | 432 | ||
433 | /* dev->mode_config.fb_lock must be held! */ | ||
434 | static void __drm_framebuffer_unregister(struct drm_device *dev, | ||
435 | struct drm_framebuffer *fb) | ||
436 | { | ||
437 | mutex_lock(&dev->mode_config.idr_mutex); | ||
438 | idr_remove(&dev->mode_config.crtc_idr, fb->base.id); | ||
439 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
440 | |||
441 | fb->base.id = 0; | ||
442 | } | ||
443 | |||
530 | static void drm_framebuffer_free(struct kref *kref) | 444 | static void drm_framebuffer_free(struct kref *kref) |
531 | { | 445 | { |
532 | struct drm_framebuffer *fb = | 446 | struct drm_framebuffer *fb = |
533 | container_of(kref, struct drm_framebuffer, refcount); | 447 | container_of(kref, struct drm_framebuffer, refcount); |
448 | struct drm_device *dev = fb->dev; | ||
449 | |||
450 | /* | ||
451 | * The lookup idr holds a weak reference, which has not necessarily been | ||
452 | * removed at this point. Check for that. | ||
453 | */ | ||
454 | mutex_lock(&dev->mode_config.fb_lock); | ||
455 | if (fb->base.id) { | ||
456 | /* Mark fb as reaped and drop idr ref. */ | ||
457 | __drm_framebuffer_unregister(dev, fb); | ||
458 | } | ||
459 | mutex_unlock(&dev->mode_config.fb_lock); | ||
460 | |||
534 | fb->funcs->destroy(fb); | 461 | fb->funcs->destroy(fb); |
535 | } | 462 | } |
536 | 463 | ||
@@ -567,8 +494,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | |||
567 | 494 | ||
568 | mutex_lock(&dev->mode_config.fb_lock); | 495 | mutex_lock(&dev->mode_config.fb_lock); |
569 | fb = __drm_framebuffer_lookup(dev, id); | 496 | fb = __drm_framebuffer_lookup(dev, id); |
570 | if (fb) | 497 | if (fb) { |
571 | drm_framebuffer_reference(fb); | 498 | if (!kref_get_unless_zero(&fb->refcount)) |
499 | fb = NULL; | ||
500 | } | ||
572 | mutex_unlock(&dev->mode_config.fb_lock); | 501 | mutex_unlock(&dev->mode_config.fb_lock); |
573 | 502 | ||
574 | return fb; | 503 | return fb; |
@@ -612,19 +541,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) | |||
612 | kref_put(&fb->refcount, drm_framebuffer_free_bug); | 541 | kref_put(&fb->refcount, drm_framebuffer_free_bug); |
613 | } | 542 | } |
614 | 543 | ||
615 | /* dev->mode_config.fb_lock must be held! */ | ||
616 | static void __drm_framebuffer_unregister(struct drm_device *dev, | ||
617 | struct drm_framebuffer *fb) | ||
618 | { | ||
619 | mutex_lock(&dev->mode_config.idr_mutex); | ||
620 | idr_remove(&dev->mode_config.crtc_idr, fb->base.id); | ||
621 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
622 | |||
623 | fb->base.id = 0; | ||
624 | |||
625 | __drm_framebuffer_unreference(fb); | ||
626 | } | ||
627 | |||
628 | /** | 544 | /** |
629 | * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr | 545 | * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr |
630 | * @fb: fb to unregister | 546 | * @fb: fb to unregister |
@@ -764,11 +680,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
764 | crtc->funcs = funcs; | 680 | crtc->funcs = funcs; |
765 | crtc->invert_dimensions = false; | 681 | crtc->invert_dimensions = false; |
766 | 682 | ||
767 | drm_modeset_lock_all(dev); | ||
768 | drm_modeset_lock_init(&crtc->mutex); | 683 | drm_modeset_lock_init(&crtc->mutex); |
769 | /* dropped by _unlock_all(): */ | ||
770 | drm_modeset_lock(&crtc->mutex, config->acquire_ctx); | ||
771 | |||
772 | 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); |
773 | if (ret) | 685 | if (ret) |
774 | goto out; | 686 | goto out; |
@@ -786,7 +698,6 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
786 | cursor->possible_crtcs = 1 << drm_crtc_index(crtc); | 698 | cursor->possible_crtcs = 1 << drm_crtc_index(crtc); |
787 | 699 | ||
788 | out: | 700 | out: |
789 | drm_modeset_unlock_all(dev); | ||
790 | 701 | ||
791 | return ret; | 702 | return ret; |
792 | } | 703 | } |
@@ -853,6 +764,59 @@ static void drm_mode_remove(struct drm_connector *connector, | |||
853 | } | 764 | } |
854 | 765 | ||
855 | /** | 766 | /** |
767 | * drm_connector_get_cmdline_mode - reads the user's cmdline mode | ||
768 | * @connector: connector to quwery | ||
769 | * @mode: returned mode | ||
770 | * | ||
771 | * The kernel supports per-connector configration of its consoles through | ||
772 | * use of the video= parameter. This function parses that option and | ||
773 | * extracts the user's specified mode (or enable/disable status) for a | ||
774 | * particular connector. This is typically only used during the early fbdev | ||
775 | * setup. | ||
776 | */ | ||
777 | static void drm_connector_get_cmdline_mode(struct drm_connector *connector) | ||
778 | { | ||
779 | struct drm_cmdline_mode *mode = &connector->cmdline_mode; | ||
780 | char *option = NULL; | ||
781 | |||
782 | if (fb_get_options(connector->name, &option)) | ||
783 | return; | ||
784 | |||
785 | if (!drm_mode_parse_command_line_for_connector(option, | ||
786 | connector, | ||
787 | mode)) | ||
788 | return; | ||
789 | |||
790 | if (mode->force) { | ||
791 | const char *s; | ||
792 | |||
793 | switch (mode->force) { | ||
794 | case DRM_FORCE_OFF: | ||
795 | s = "OFF"; | ||
796 | break; | ||
797 | case DRM_FORCE_ON_DIGITAL: | ||
798 | s = "ON - dig"; | ||
799 | break; | ||
800 | default: | ||
801 | case DRM_FORCE_ON: | ||
802 | s = "ON"; | ||
803 | break; | ||
804 | } | ||
805 | |||
806 | DRM_INFO("forcing %s connector %s\n", connector->name, s); | ||
807 | connector->force = mode->force; | ||
808 | } | ||
809 | |||
810 | DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", | ||
811 | connector->name, | ||
812 | mode->xres, mode->yres, | ||
813 | mode->refresh_specified ? mode->refresh : 60, | ||
814 | mode->rb ? " reduced blanking" : "", | ||
815 | mode->margins ? " with margins" : "", | ||
816 | mode->interlace ? " interlaced" : ""); | ||
817 | } | ||
818 | |||
819 | /** | ||
856 | * drm_connector_init - Init a preallocated connector | 820 | * drm_connector_init - Init a preallocated connector |
857 | * @dev: DRM device | 821 | * @dev: DRM device |
858 | * @connector: the connector to init | 822 | * @connector: the connector to init |
@@ -904,6 +868,8 @@ int drm_connector_init(struct drm_device *dev, | |||
904 | connector->edid_blob_ptr = NULL; | 868 | connector->edid_blob_ptr = NULL; |
905 | connector->status = connector_status_unknown; | 869 | connector->status = connector_status_unknown; |
906 | 870 | ||
871 | drm_connector_get_cmdline_mode(connector); | ||
872 | |||
907 | list_add_tail(&connector->head, &dev->mode_config.connector_list); | 873 | list_add_tail(&connector->head, &dev->mode_config.connector_list); |
908 | dev->mode_config.num_connector++; | 874 | dev->mode_config.num_connector++; |
909 | 875 | ||
@@ -957,6 +923,29 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
957 | EXPORT_SYMBOL(drm_connector_cleanup); | 923 | EXPORT_SYMBOL(drm_connector_cleanup); |
958 | 924 | ||
959 | /** | 925 | /** |
926 | * drm_connector_index - find the index of a registered connector | ||
927 | * @connector: connector to find index for | ||
928 | * | ||
929 | * Given a registered connector, return the index of that connector within a DRM | ||
930 | * device's list of connectors. | ||
931 | */ | ||
932 | unsigned int drm_connector_index(struct drm_connector *connector) | ||
933 | { | ||
934 | unsigned int index = 0; | ||
935 | struct drm_connector *tmp; | ||
936 | |||
937 | list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { | ||
938 | if (tmp == connector) | ||
939 | return index; | ||
940 | |||
941 | index++; | ||
942 | } | ||
943 | |||
944 | BUG(); | ||
945 | } | ||
946 | EXPORT_SYMBOL(drm_connector_index); | ||
947 | |||
948 | /** | ||
960 | * drm_connector_register - register a connector | 949 | * drm_connector_register - register a connector |
961 | * @connector: the connector to register | 950 | * @connector: the connector to register |
962 | * | 951 | * |
@@ -1261,6 +1250,29 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
1261 | EXPORT_SYMBOL(drm_plane_cleanup); | 1250 | EXPORT_SYMBOL(drm_plane_cleanup); |
1262 | 1251 | ||
1263 | /** | 1252 | /** |
1253 | * drm_plane_index - find the index of a registered plane | ||
1254 | * @plane: plane to find index for | ||
1255 | * | ||
1256 | * Given a registered plane, return the index of that CRTC within a DRM | ||
1257 | * device's list of planes. | ||
1258 | */ | ||
1259 | unsigned int drm_plane_index(struct drm_plane *plane) | ||
1260 | { | ||
1261 | unsigned int index = 0; | ||
1262 | struct drm_plane *tmp; | ||
1263 | |||
1264 | list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { | ||
1265 | if (tmp == plane) | ||
1266 | return index; | ||
1267 | |||
1268 | index++; | ||
1269 | } | ||
1270 | |||
1271 | BUG(); | ||
1272 | } | ||
1273 | EXPORT_SYMBOL(drm_plane_index); | ||
1274 | |||
1275 | /** | ||
1264 | * drm_plane_force_disable - Forcibly disable a plane | 1276 | * drm_plane_force_disable - Forcibly disable a plane |
1265 | * @plane: plane to disable | 1277 | * @plane: plane to disable |
1266 | * | 1278 | * |
@@ -1271,19 +1283,21 @@ EXPORT_SYMBOL(drm_plane_cleanup); | |||
1271 | */ | 1283 | */ |
1272 | void drm_plane_force_disable(struct drm_plane *plane) | 1284 | void drm_plane_force_disable(struct drm_plane *plane) |
1273 | { | 1285 | { |
1274 | struct drm_framebuffer *old_fb = plane->fb; | ||
1275 | int ret; | 1286 | int ret; |
1276 | 1287 | ||
1277 | if (!old_fb) | 1288 | if (!plane->fb) |
1278 | return; | 1289 | return; |
1279 | 1290 | ||
1291 | plane->old_fb = plane->fb; | ||
1280 | ret = plane->funcs->disable_plane(plane); | 1292 | ret = plane->funcs->disable_plane(plane); |
1281 | if (ret) { | 1293 | if (ret) { |
1282 | DRM_ERROR("failed to disable plane with busy fb\n"); | 1294 | DRM_ERROR("failed to disable plane with busy fb\n"); |
1295 | plane->old_fb = NULL; | ||
1283 | return; | 1296 | return; |
1284 | } | 1297 | } |
1285 | /* disconnect the plane from the fb and crtc: */ | 1298 | /* disconnect the plane from the fb and crtc: */ |
1286 | __drm_framebuffer_unreference(old_fb); | 1299 | __drm_framebuffer_unreference(plane->old_fb); |
1300 | plane->old_fb = NULL; | ||
1287 | plane->fb = NULL; | 1301 | plane->fb = NULL; |
1288 | plane->crtc = NULL; | 1302 | plane->crtc = NULL; |
1289 | } | 1303 | } |
@@ -2249,33 +2263,29 @@ out: | |||
2249 | * | 2263 | * |
2250 | * src_{x,y,w,h} are provided in 16.16 fixed point format | 2264 | * src_{x,y,w,h} are provided in 16.16 fixed point format |
2251 | */ | 2265 | */ |
2252 | static int setplane_internal(struct drm_plane *plane, | 2266 | static int __setplane_internal(struct drm_plane *plane, |
2253 | struct drm_crtc *crtc, | 2267 | struct drm_crtc *crtc, |
2254 | struct drm_framebuffer *fb, | 2268 | struct drm_framebuffer *fb, |
2255 | int32_t crtc_x, int32_t crtc_y, | 2269 | int32_t crtc_x, int32_t crtc_y, |
2256 | uint32_t crtc_w, uint32_t crtc_h, | 2270 | uint32_t crtc_w, uint32_t crtc_h, |
2257 | /* src_{x,y,w,h} values are 16.16 fixed point */ | 2271 | /* src_{x,y,w,h} values are 16.16 fixed point */ |
2258 | uint32_t src_x, uint32_t src_y, | 2272 | uint32_t src_x, uint32_t src_y, |
2259 | uint32_t src_w, uint32_t src_h) | 2273 | uint32_t src_w, uint32_t src_h) |
2260 | { | 2274 | { |
2261 | struct drm_device *dev = plane->dev; | ||
2262 | struct drm_framebuffer *old_fb = NULL; | ||
2263 | int ret = 0; | 2275 | int ret = 0; |
2264 | unsigned int fb_width, fb_height; | 2276 | unsigned int fb_width, fb_height; |
2265 | int i; | 2277 | int i; |
2266 | 2278 | ||
2267 | /* No fb means shut it down */ | 2279 | /* No fb means shut it down */ |
2268 | if (!fb) { | 2280 | if (!fb) { |
2269 | drm_modeset_lock_all(dev); | 2281 | plane->old_fb = plane->fb; |
2270 | old_fb = plane->fb; | ||
2271 | ret = plane->funcs->disable_plane(plane); | 2282 | ret = plane->funcs->disable_plane(plane); |
2272 | if (!ret) { | 2283 | if (!ret) { |
2273 | plane->crtc = NULL; | 2284 | plane->crtc = NULL; |
2274 | plane->fb = NULL; | 2285 | plane->fb = NULL; |
2275 | } else { | 2286 | } else { |
2276 | old_fb = NULL; | 2287 | plane->old_fb = NULL; |
2277 | } | 2288 | } |
2278 | drm_modeset_unlock_all(dev); | ||
2279 | goto out; | 2289 | goto out; |
2280 | } | 2290 | } |
2281 | 2291 | ||
@@ -2315,8 +2325,7 @@ static int setplane_internal(struct drm_plane *plane, | |||
2315 | goto out; | 2325 | goto out; |
2316 | } | 2326 | } |
2317 | 2327 | ||
2318 | drm_modeset_lock_all(dev); | 2328 | plane->old_fb = plane->fb; |
2319 | old_fb = plane->fb; | ||
2320 | ret = plane->funcs->update_plane(plane, crtc, fb, | 2329 | ret = plane->funcs->update_plane(plane, crtc, fb, |
2321 | crtc_x, crtc_y, crtc_w, crtc_h, | 2330 | crtc_x, crtc_y, crtc_w, crtc_h, |
2322 | src_x, src_y, src_w, src_h); | 2331 | src_x, src_y, src_w, src_h); |
@@ -2325,18 +2334,37 @@ static int setplane_internal(struct drm_plane *plane, | |||
2325 | plane->fb = fb; | 2334 | plane->fb = fb; |
2326 | fb = NULL; | 2335 | fb = NULL; |
2327 | } else { | 2336 | } else { |
2328 | old_fb = NULL; | 2337 | plane->old_fb = NULL; |
2329 | } | 2338 | } |
2330 | drm_modeset_unlock_all(dev); | ||
2331 | 2339 | ||
2332 | out: | 2340 | out: |
2333 | if (fb) | 2341 | if (fb) |
2334 | drm_framebuffer_unreference(fb); | 2342 | drm_framebuffer_unreference(fb); |
2335 | if (old_fb) | 2343 | if (plane->old_fb) |
2336 | drm_framebuffer_unreference(old_fb); | 2344 | drm_framebuffer_unreference(plane->old_fb); |
2345 | plane->old_fb = NULL; | ||
2337 | 2346 | ||
2338 | return ret; | 2347 | return ret; |
2348 | } | ||
2349 | |||
2350 | static int setplane_internal(struct drm_plane *plane, | ||
2351 | struct drm_crtc *crtc, | ||
2352 | struct drm_framebuffer *fb, | ||
2353 | int32_t crtc_x, int32_t crtc_y, | ||
2354 | uint32_t crtc_w, uint32_t crtc_h, | ||
2355 | /* src_{x,y,w,h} values are 16.16 fixed point */ | ||
2356 | uint32_t src_x, uint32_t src_y, | ||
2357 | uint32_t src_w, uint32_t src_h) | ||
2358 | { | ||
2359 | int ret; | ||
2360 | |||
2361 | drm_modeset_lock_all(plane->dev); | ||
2362 | ret = __setplane_internal(plane, crtc, fb, | ||
2363 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
2364 | src_x, src_y, src_w, src_h); | ||
2365 | drm_modeset_unlock_all(plane->dev); | ||
2339 | 2366 | ||
2367 | return ret; | ||
2340 | } | 2368 | } |
2341 | 2369 | ||
2342 | /** | 2370 | /** |
@@ -2440,7 +2468,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) | |||
2440 | * crtcs. Atomic modeset will have saner semantics ... | 2468 | * crtcs. Atomic modeset will have saner semantics ... |
2441 | */ | 2469 | */ |
2442 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) | 2470 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) |
2443 | tmp->old_fb = tmp->primary->fb; | 2471 | tmp->primary->old_fb = tmp->primary->fb; |
2444 | 2472 | ||
2445 | fb = set->fb; | 2473 | fb = set->fb; |
2446 | 2474 | ||
@@ -2453,8 +2481,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) | |||
2453 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { | 2481 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { |
2454 | if (tmp->primary->fb) | 2482 | if (tmp->primary->fb) |
2455 | drm_framebuffer_reference(tmp->primary->fb); | 2483 | drm_framebuffer_reference(tmp->primary->fb); |
2456 | if (tmp->old_fb) | 2484 | if (tmp->primary->old_fb) |
2457 | drm_framebuffer_unreference(tmp->old_fb); | 2485 | drm_framebuffer_unreference(tmp->primary->old_fb); |
2486 | tmp->primary->old_fb = NULL; | ||
2458 | } | 2487 | } |
2459 | 2488 | ||
2460 | return ret; | 2489 | return ret; |
@@ -2701,6 +2730,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, | |||
2701 | int ret = 0; | 2730 | int ret = 0; |
2702 | 2731 | ||
2703 | BUG_ON(!crtc->cursor); | 2732 | BUG_ON(!crtc->cursor); |
2733 | WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); | ||
2704 | 2734 | ||
2705 | /* | 2735 | /* |
2706 | * Obtain fb we'll be using (either new or existing) and take an extra | 2736 | * Obtain fb we'll be using (either new or existing) and take an extra |
@@ -2720,11 +2750,9 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, | |||
2720 | fb = NULL; | 2750 | fb = NULL; |
2721 | } | 2751 | } |
2722 | } else { | 2752 | } else { |
2723 | mutex_lock(&dev->mode_config.mutex); | ||
2724 | fb = crtc->cursor->fb; | 2753 | fb = crtc->cursor->fb; |
2725 | if (fb) | 2754 | if (fb) |
2726 | drm_framebuffer_reference(fb); | 2755 | drm_framebuffer_reference(fb); |
2727 | mutex_unlock(&dev->mode_config.mutex); | ||
2728 | } | 2756 | } |
2729 | 2757 | ||
2730 | if (req->flags & DRM_MODE_CURSOR_MOVE) { | 2758 | if (req->flags & DRM_MODE_CURSOR_MOVE) { |
@@ -2746,7 +2774,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, | |||
2746 | * setplane_internal will take care of deref'ing either the old or new | 2774 | * setplane_internal will take care of deref'ing either the old or new |
2747 | * framebuffer depending on success. | 2775 | * framebuffer depending on success. |
2748 | */ | 2776 | */ |
2749 | ret = setplane_internal(crtc->cursor, crtc, fb, | 2777 | ret = __setplane_internal(crtc->cursor, crtc, fb, |
2750 | crtc_x, crtc_y, crtc_w, crtc_h, | 2778 | crtc_x, crtc_y, crtc_w, crtc_h, |
2751 | 0, 0, src_w, src_h); | 2779 | 0, 0, src_w, src_h); |
2752 | 2780 | ||
@@ -2782,10 +2810,12 @@ static int drm_mode_cursor_common(struct drm_device *dev, | |||
2782 | * If this crtc has a universal cursor plane, call that plane's update | 2810 | * If this crtc has a universal cursor plane, call that plane's update |
2783 | * handler rather than using legacy cursor handlers. | 2811 | * handler rather than using legacy cursor handlers. |
2784 | */ | 2812 | */ |
2785 | if (crtc->cursor) | 2813 | drm_modeset_lock_crtc(crtc); |
2786 | return drm_mode_cursor_universal(crtc, req, file_priv); | 2814 | if (crtc->cursor) { |
2815 | ret = drm_mode_cursor_universal(crtc, req, file_priv); | ||
2816 | goto out; | ||
2817 | } | ||
2787 | 2818 | ||
2788 | drm_modeset_lock(&crtc->mutex, NULL); | ||
2789 | if (req->flags & DRM_MODE_CURSOR_BO) { | 2819 | if (req->flags & DRM_MODE_CURSOR_BO) { |
2790 | if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { | 2820 | if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { |
2791 | ret = -ENXIO; | 2821 | ret = -ENXIO; |
@@ -2809,7 +2839,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, | |||
2809 | } | 2839 | } |
2810 | } | 2840 | } |
2811 | out: | 2841 | out: |
2812 | drm_modeset_unlock(&crtc->mutex); | 2842 | drm_modeset_unlock_crtc(crtc); |
2813 | 2843 | ||
2814 | return ret; | 2844 | return ret; |
2815 | 2845 | ||
@@ -3370,7 +3400,16 @@ void drm_fb_release(struct drm_file *priv) | |||
3370 | struct drm_device *dev = priv->minor->dev; | 3400 | struct drm_device *dev = priv->minor->dev; |
3371 | struct drm_framebuffer *fb, *tfb; | 3401 | struct drm_framebuffer *fb, *tfb; |
3372 | 3402 | ||
3373 | mutex_lock(&priv->fbs_lock); | 3403 | /* |
3404 | * 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 | ||
3406 | * avoid upsetting lockdep since the universal cursor code adds a | ||
3407 | * framebuffer while holding mutex locks. | ||
3408 | * | ||
3409 | * Note that a real deadlock between fpriv->fbs_lock and the modeset | ||
3410 | * locks is impossible here since no one else but this function can get | ||
3411 | * at it any more. | ||
3412 | */ | ||
3374 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { | 3413 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { |
3375 | 3414 | ||
3376 | mutex_lock(&dev->mode_config.fb_lock); | 3415 | mutex_lock(&dev->mode_config.fb_lock); |
@@ -3383,7 +3422,6 @@ void drm_fb_release(struct drm_file *priv) | |||
3383 | /* This will also drop the fpriv->fbs reference. */ | 3422 | /* This will also drop the fpriv->fbs reference. */ |
3384 | drm_framebuffer_remove(fb); | 3423 | drm_framebuffer_remove(fb); |
3385 | } | 3424 | } |
3386 | mutex_unlock(&priv->fbs_lock); | ||
3387 | } | 3425 | } |
3388 | 3426 | ||
3389 | /** | 3427 | /** |
@@ -3495,9 +3533,10 @@ EXPORT_SYMBOL(drm_property_create_enum); | |||
3495 | * @flags: flags specifying the property type | 3533 | * @flags: flags specifying the property type |
3496 | * @name: name of the property | 3534 | * @name: name of the property |
3497 | * @props: enumeration lists with property bitflags | 3535 | * @props: enumeration lists with property bitflags |
3498 | * @num_values: number of pre-defined values | 3536 | * @num_props: size of the @props array |
3537 | * @supported_bits: bitmask of all supported enumeration values | ||
3499 | * | 3538 | * |
3500 | * This creates a new generic drm property which can then be attached to a drm | 3539 | * This creates a new bitmask drm property which can then be attached to a drm |
3501 | * object with drm_object_attach_property. The returned property object must be | 3540 | * object with drm_object_attach_property. The returned property object must be |
3502 | * freed with drm_property_destroy. | 3541 | * freed with drm_property_destroy. |
3503 | * | 3542 | * |
@@ -4157,12 +4196,25 @@ static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, | |||
4157 | return ret; | 4196 | return ret; |
4158 | } | 4197 | } |
4159 | 4198 | ||
4160 | static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, | 4199 | /** |
4161 | struct drm_property *property, | 4200 | * drm_mode_plane_set_obj_prop - set the value of a property |
4162 | uint64_t value) | 4201 | * @plane: drm plane object to set property value for |
4202 | * @property: property to set | ||
4203 | * @value: value the property should be set to | ||
4204 | * | ||
4205 | * This functions sets a given property on a given plane object. This function | ||
4206 | * calls the driver's ->set_property callback and changes the software state of | ||
4207 | * the property if the callback succeeds. | ||
4208 | * | ||
4209 | * Returns: | ||
4210 | * Zero on success, error code on failure. | ||
4211 | */ | ||
4212 | int drm_mode_plane_set_obj_prop(struct drm_plane *plane, | ||
4213 | struct drm_property *property, | ||
4214 | uint64_t value) | ||
4163 | { | 4215 | { |
4164 | int ret = -EINVAL; | 4216 | int ret = -EINVAL; |
4165 | struct drm_plane *plane = obj_to_plane(obj); | 4217 | struct drm_mode_object *obj = &plane->base; |
4166 | 4218 | ||
4167 | if (plane->funcs->set_property) | 4219 | if (plane->funcs->set_property) |
4168 | ret = plane->funcs->set_property(plane, property, value); | 4220 | ret = plane->funcs->set_property(plane, property, value); |
@@ -4171,6 +4223,7 @@ static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, | |||
4171 | 4223 | ||
4172 | return ret; | 4224 | return ret; |
4173 | } | 4225 | } |
4226 | EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); | ||
4174 | 4227 | ||
4175 | /** | 4228 | /** |
4176 | * drm_mode_getproperty_ioctl - get the current value of a object's property | 4229 | * drm_mode_getproperty_ioctl - get the current value of a object's property |
@@ -4309,7 +4362,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
4309 | ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); | 4362 | ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); |
4310 | break; | 4363 | break; |
4311 | case DRM_MODE_OBJECT_PLANE: | 4364 | case DRM_MODE_OBJECT_PLANE: |
4312 | ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value); | 4365 | ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), |
4366 | property, arg->value); | ||
4313 | break; | 4367 | break; |
4314 | } | 4368 | } |
4315 | 4369 | ||
@@ -4529,7 +4583,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4529 | { | 4583 | { |
4530 | struct drm_mode_crtc_page_flip *page_flip = data; | 4584 | struct drm_mode_crtc_page_flip *page_flip = data; |
4531 | struct drm_crtc *crtc; | 4585 | struct drm_crtc *crtc; |
4532 | struct drm_framebuffer *fb = NULL, *old_fb = NULL; | 4586 | struct drm_framebuffer *fb = NULL; |
4533 | struct drm_pending_vblank_event *e = NULL; | 4587 | struct drm_pending_vblank_event *e = NULL; |
4534 | unsigned long flags; | 4588 | unsigned long flags; |
4535 | int ret = -EINVAL; | 4589 | int ret = -EINVAL; |
@@ -4545,7 +4599,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4545 | if (!crtc) | 4599 | if (!crtc) |
4546 | return -ENOENT; | 4600 | return -ENOENT; |
4547 | 4601 | ||
4548 | drm_modeset_lock(&crtc->mutex, NULL); | 4602 | drm_modeset_lock_crtc(crtc); |
4549 | if (crtc->primary->fb == NULL) { | 4603 | if (crtc->primary->fb == NULL) { |
4550 | /* The framebuffer is currently unbound, presumably | 4604 | /* The framebuffer is currently unbound, presumably |
4551 | * due to a hotplug event, that userspace has not | 4605 | * due to a hotplug event, that userspace has not |
@@ -4601,7 +4655,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4601 | (void (*) (struct drm_pending_event *)) kfree; | 4655 | (void (*) (struct drm_pending_event *)) kfree; |
4602 | } | 4656 | } |
4603 | 4657 | ||
4604 | old_fb = crtc->primary->fb; | 4658 | crtc->primary->old_fb = crtc->primary->fb; |
4605 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | 4659 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); |
4606 | if (ret) { | 4660 | if (ret) { |
4607 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | 4661 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { |
@@ -4611,7 +4665,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4611 | kfree(e); | 4665 | kfree(e); |
4612 | } | 4666 | } |
4613 | /* Keep the old fb, don't unref it. */ | 4667 | /* Keep the old fb, don't unref it. */ |
4614 | old_fb = NULL; | 4668 | crtc->primary->old_fb = NULL; |
4615 | } else { | 4669 | } else { |
4616 | /* | 4670 | /* |
4617 | * Warn if the driver hasn't properly updated the crtc->fb | 4671 | * Warn if the driver hasn't properly updated the crtc->fb |
@@ -4627,9 +4681,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4627 | out: | 4681 | out: |
4628 | if (fb) | 4682 | if (fb) |
4629 | drm_framebuffer_unreference(fb); | 4683 | drm_framebuffer_unreference(fb); |
4630 | if (old_fb) | 4684 | if (crtc->primary->old_fb) |
4631 | drm_framebuffer_unreference(old_fb); | 4685 | drm_framebuffer_unreference(crtc->primary->old_fb); |
4632 | drm_modeset_unlock(&crtc->mutex); | 4686 | crtc->primary->old_fb = NULL; |
4687 | drm_modeset_unlock_crtc(crtc); | ||
4633 | 4688 | ||
4634 | return ret; | 4689 | return ret; |
4635 | } | 4690 | } |
@@ -4645,9 +4700,14 @@ out: | |||
4645 | void drm_mode_config_reset(struct drm_device *dev) | 4700 | void drm_mode_config_reset(struct drm_device *dev) |
4646 | { | 4701 | { |
4647 | struct drm_crtc *crtc; | 4702 | struct drm_crtc *crtc; |
4703 | struct drm_plane *plane; | ||
4648 | struct drm_encoder *encoder; | 4704 | struct drm_encoder *encoder; |
4649 | struct drm_connector *connector; | 4705 | struct drm_connector *connector; |
4650 | 4706 | ||
4707 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) | ||
4708 | if (plane->funcs->reset) | ||
4709 | plane->funcs->reset(plane); | ||
4710 | |||
4651 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | 4711 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) |
4652 | if (crtc->funcs->reset) | 4712 | if (crtc->funcs->reset) |
4653 | crtc->funcs->reset(crtc); | 4713 | crtc->funcs->reset(crtc); |