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); |
