diff options
author | Dave Airlie <airlied@redhat.com> | 2014-08-25 19:04:03 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-08-25 19:04:03 -0400 |
commit | c0ee755fc57319a623e0d9ef839cf8fb26ce8d60 (patch) | |
tree | 727fe78a158757f75b54d7e037b383ad6a39843c /drivers | |
parent | 52addcf9d6669fa439387610bc65c92fa0980cef (diff) | |
parent | 14f476fa24e81d0beea1aa14d763102958518d60 (diff) |
Merge tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel into drm-next
So small drm stuff all over for 3.18. Biggest one is the cmdline parsing
from Chris with a few fixes from me to make it work for stupid kernel
configs.
Plus the atomic prep series.
Tested for more than a week in -nightly and Ville/Imre indeed discovered
some fun which is now fixed (and i915 vblank patches postponed since the
fixups need this branch plus drm-intel-next merged together).
* tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel:
drm: Use the type of the array element when reallocating
drm: Don't return 0 for a value used as a denominator
drm: Docbook fixes
drm/irq: Implement a generic vblank_wait function
drm: Add a plane->reset hook
drm: trylock modest locking for fbdev panics
drm: Move ->old_fb from crtc to plane
drm: Handle legacy per-crtc locking with full acquire ctx
drm: Move modeset_lock_all helpers to drm_modeset_lock.[hc]
drm: Add drm_plane/connector_index
drm: idiot-proof vblank
drm: Warn when leaking flip events on close
drm: Perform cmdline mode parsing during connector initialisation
video/fbdev: Always built-in video= cmdline parsing
drm: Don't grab an fb reference for the idr
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 306 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 68 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_modes.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_modeset_lock.c | 213 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_probe_helper.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_mode.c | 21 | ||||
-rw-r--r-- | drivers/video/fbdev/Kconfig | 4 | ||||
-rw-r--r-- | drivers/video/fbdev/core/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fb_cmdline.c | 110 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 92 | ||||
-rw-r--r-- | drivers/video/fbdev/core/modedb.c | 3 |
16 files changed, 598 insertions, 322 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index b066bb3ca01a..e251ecce4ed2 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -8,6 +8,7 @@ menuconfig DRM | |||
8 | tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" | 8 | tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" |
9 | depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA | 9 | depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA |
10 | select HDMI | 10 | select HDMI |
11 | select FB_CMDLINE | ||
11 | select I2C | 12 | select I2C |
12 | select I2C_ALGOBIT | 13 | select I2C_ALGOBIT |
13 | select DMA_SHARED_BUFFER | 14 | select DMA_SHARED_BUFFER |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fa2be249999c..f09b75212081 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -45,101 +45,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, | |||
45 | struct drm_mode_fb_cmd2 *r, | 45 | struct drm_mode_fb_cmd2 *r, |
46 | struct drm_file *file_priv); | 46 | struct drm_file *file_priv); |
47 | 47 | ||
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. */ | 48 | /* Avoid boilerplate. I'm tired of typing. */ |
144 | #define DRM_ENUM_NAME_FN(fnname, list) \ | 49 | #define DRM_ENUM_NAME_FN(fnname, list) \ |
145 | const char *fnname(int val) \ | 50 | const char *fnname(int val) \ |
@@ -515,9 +420,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | |||
515 | if (ret) | 420 | if (ret) |
516 | goto out; | 421 | goto out; |
517 | 422 | ||
518 | /* Grab the idr reference. */ | ||
519 | drm_framebuffer_reference(fb); | ||
520 | |||
521 | dev->mode_config.num_fb++; | 423 | dev->mode_config.num_fb++; |
522 | list_add(&fb->head, &dev->mode_config.fb_list); | 424 | list_add(&fb->head, &dev->mode_config.fb_list); |
523 | out: | 425 | out: |
@@ -527,10 +429,34 @@ out: | |||
527 | } | 429 | } |
528 | EXPORT_SYMBOL(drm_framebuffer_init); | 430 | EXPORT_SYMBOL(drm_framebuffer_init); |
529 | 431 | ||
432 | /* dev->mode_config.fb_lock must be held! */ | ||
433 | static void __drm_framebuffer_unregister(struct drm_device *dev, | ||
434 | struct drm_framebuffer *fb) | ||
435 | { | ||
436 | mutex_lock(&dev->mode_config.idr_mutex); | ||
437 | idr_remove(&dev->mode_config.crtc_idr, fb->base.id); | ||
438 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
439 | |||
440 | fb->base.id = 0; | ||
441 | } | ||
442 | |||
530 | static void drm_framebuffer_free(struct kref *kref) | 443 | static void drm_framebuffer_free(struct kref *kref) |
531 | { | 444 | { |
532 | struct drm_framebuffer *fb = | 445 | struct drm_framebuffer *fb = |
533 | container_of(kref, struct drm_framebuffer, refcount); | 446 | container_of(kref, struct drm_framebuffer, refcount); |
447 | struct drm_device *dev = fb->dev; | ||
448 | |||
449 | /* | ||
450 | * The lookup idr holds a weak reference, which has not necessarily been | ||
451 | * removed at this point. Check for that. | ||
452 | */ | ||
453 | mutex_lock(&dev->mode_config.fb_lock); | ||
454 | if (fb->base.id) { | ||
455 | /* Mark fb as reaped and drop idr ref. */ | ||
456 | __drm_framebuffer_unregister(dev, fb); | ||
457 | } | ||
458 | mutex_unlock(&dev->mode_config.fb_lock); | ||
459 | |||
534 | fb->funcs->destroy(fb); | 460 | fb->funcs->destroy(fb); |
535 | } | 461 | } |
536 | 462 | ||
@@ -567,8 +493,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | |||
567 | 493 | ||
568 | mutex_lock(&dev->mode_config.fb_lock); | 494 | mutex_lock(&dev->mode_config.fb_lock); |
569 | fb = __drm_framebuffer_lookup(dev, id); | 495 | fb = __drm_framebuffer_lookup(dev, id); |
570 | if (fb) | 496 | if (fb) { |
571 | drm_framebuffer_reference(fb); | 497 | if (!kref_get_unless_zero(&fb->refcount)) |
498 | fb = NULL; | ||
499 | } | ||
572 | mutex_unlock(&dev->mode_config.fb_lock); | 500 | mutex_unlock(&dev->mode_config.fb_lock); |
573 | 501 | ||
574 | return fb; | 502 | return fb; |
@@ -612,19 +540,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) | |||
612 | kref_put(&fb->refcount, drm_framebuffer_free_bug); | 540 | kref_put(&fb->refcount, drm_framebuffer_free_bug); |
613 | } | 541 | } |
614 | 542 | ||
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 | /** | 543 | /** |
629 | * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr | 544 | * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr |
630 | * @fb: fb to unregister | 545 | * @fb: fb to unregister |
@@ -853,6 +768,59 @@ static void drm_mode_remove(struct drm_connector *connector, | |||
853 | } | 768 | } |
854 | 769 | ||
855 | /** | 770 | /** |
771 | * drm_connector_get_cmdline_mode - reads the user's cmdline mode | ||
772 | * @connector: connector to quwery | ||
773 | * @mode: returned mode | ||
774 | * | ||
775 | * The kernel supports per-connector configration of its consoles through | ||
776 | * use of the video= parameter. This function parses that option and | ||
777 | * extracts the user's specified mode (or enable/disable status) for a | ||
778 | * particular connector. This is typically only used during the early fbdev | ||
779 | * setup. | ||
780 | */ | ||
781 | static void drm_connector_get_cmdline_mode(struct drm_connector *connector) | ||
782 | { | ||
783 | struct drm_cmdline_mode *mode = &connector->cmdline_mode; | ||
784 | char *option = NULL; | ||
785 | |||
786 | if (fb_get_options(connector->name, &option)) | ||
787 | return; | ||
788 | |||
789 | if (!drm_mode_parse_command_line_for_connector(option, | ||
790 | connector, | ||
791 | mode)) | ||
792 | return; | ||
793 | |||
794 | if (mode->force) { | ||
795 | const char *s; | ||
796 | |||
797 | switch (mode->force) { | ||
798 | case DRM_FORCE_OFF: | ||
799 | s = "OFF"; | ||
800 | break; | ||
801 | case DRM_FORCE_ON_DIGITAL: | ||
802 | s = "ON - dig"; | ||
803 | break; | ||
804 | default: | ||
805 | case DRM_FORCE_ON: | ||
806 | s = "ON"; | ||
807 | break; | ||
808 | } | ||
809 | |||
810 | DRM_INFO("forcing %s connector %s\n", connector->name, s); | ||
811 | connector->force = mode->force; | ||
812 | } | ||
813 | |||
814 | DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", | ||
815 | connector->name, | ||
816 | mode->xres, mode->yres, | ||
817 | mode->refresh_specified ? mode->refresh : 60, | ||
818 | mode->rb ? " reduced blanking" : "", | ||
819 | mode->margins ? " with margins" : "", | ||
820 | mode->interlace ? " interlaced" : ""); | ||
821 | } | ||
822 | |||
823 | /** | ||
856 | * drm_connector_init - Init a preallocated connector | 824 | * drm_connector_init - Init a preallocated connector |
857 | * @dev: DRM device | 825 | * @dev: DRM device |
858 | * @connector: the connector to init | 826 | * @connector: the connector to init |
@@ -904,6 +872,8 @@ int drm_connector_init(struct drm_device *dev, | |||
904 | connector->edid_blob_ptr = NULL; | 872 | connector->edid_blob_ptr = NULL; |
905 | connector->status = connector_status_unknown; | 873 | connector->status = connector_status_unknown; |
906 | 874 | ||
875 | drm_connector_get_cmdline_mode(connector); | ||
876 | |||
907 | list_add_tail(&connector->head, &dev->mode_config.connector_list); | 877 | list_add_tail(&connector->head, &dev->mode_config.connector_list); |
908 | dev->mode_config.num_connector++; | 878 | dev->mode_config.num_connector++; |
909 | 879 | ||
@@ -957,6 +927,29 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
957 | EXPORT_SYMBOL(drm_connector_cleanup); | 927 | EXPORT_SYMBOL(drm_connector_cleanup); |
958 | 928 | ||
959 | /** | 929 | /** |
930 | * drm_connector_index - find the index of a registered connector | ||
931 | * @connector: connector to find index for | ||
932 | * | ||
933 | * Given a registered connector, return the index of that connector within a DRM | ||
934 | * device's list of connectors. | ||
935 | */ | ||
936 | unsigned int drm_connector_index(struct drm_connector *connector) | ||
937 | { | ||
938 | unsigned int index = 0; | ||
939 | struct drm_connector *tmp; | ||
940 | |||
941 | list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { | ||
942 | if (tmp == connector) | ||
943 | return index; | ||
944 | |||
945 | index++; | ||
946 | } | ||
947 | |||
948 | BUG(); | ||
949 | } | ||
950 | EXPORT_SYMBOL(drm_connector_index); | ||
951 | |||
952 | /** | ||
960 | * drm_connector_register - register a connector | 953 | * drm_connector_register - register a connector |
961 | * @connector: the connector to register | 954 | * @connector: the connector to register |
962 | * | 955 | * |
@@ -1261,6 +1254,29 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
1261 | EXPORT_SYMBOL(drm_plane_cleanup); | 1254 | EXPORT_SYMBOL(drm_plane_cleanup); |
1262 | 1255 | ||
1263 | /** | 1256 | /** |
1257 | * drm_plane_index - find the index of a registered plane | ||
1258 | * @plane: plane to find index for | ||
1259 | * | ||
1260 | * Given a registered plane, return the index of that CRTC within a DRM | ||
1261 | * device's list of planes. | ||
1262 | */ | ||
1263 | unsigned int drm_plane_index(struct drm_plane *plane) | ||
1264 | { | ||
1265 | unsigned int index = 0; | ||
1266 | struct drm_plane *tmp; | ||
1267 | |||
1268 | list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { | ||
1269 | if (tmp == plane) | ||
1270 | return index; | ||
1271 | |||
1272 | index++; | ||
1273 | } | ||
1274 | |||
1275 | BUG(); | ||
1276 | } | ||
1277 | EXPORT_SYMBOL(drm_plane_index); | ||
1278 | |||
1279 | /** | ||
1264 | * drm_plane_force_disable - Forcibly disable a plane | 1280 | * drm_plane_force_disable - Forcibly disable a plane |
1265 | * @plane: plane to disable | 1281 | * @plane: plane to disable |
1266 | * | 1282 | * |
@@ -1271,19 +1287,21 @@ EXPORT_SYMBOL(drm_plane_cleanup); | |||
1271 | */ | 1287 | */ |
1272 | void drm_plane_force_disable(struct drm_plane *plane) | 1288 | void drm_plane_force_disable(struct drm_plane *plane) |
1273 | { | 1289 | { |
1274 | struct drm_framebuffer *old_fb = plane->fb; | ||
1275 | int ret; | 1290 | int ret; |
1276 | 1291 | ||
1277 | if (!old_fb) | 1292 | if (!plane->fb) |
1278 | return; | 1293 | return; |
1279 | 1294 | ||
1295 | plane->old_fb = plane->fb; | ||
1280 | ret = plane->funcs->disable_plane(plane); | 1296 | ret = plane->funcs->disable_plane(plane); |
1281 | if (ret) { | 1297 | if (ret) { |
1282 | DRM_ERROR("failed to disable plane with busy fb\n"); | 1298 | DRM_ERROR("failed to disable plane with busy fb\n"); |
1299 | plane->old_fb = NULL; | ||
1283 | return; | 1300 | return; |
1284 | } | 1301 | } |
1285 | /* disconnect the plane from the fb and crtc: */ | 1302 | /* disconnect the plane from the fb and crtc: */ |
1286 | __drm_framebuffer_unreference(old_fb); | 1303 | __drm_framebuffer_unreference(plane->old_fb); |
1304 | plane->old_fb = NULL; | ||
1287 | plane->fb = NULL; | 1305 | plane->fb = NULL; |
1288 | plane->crtc = NULL; | 1306 | plane->crtc = NULL; |
1289 | } | 1307 | } |
@@ -2259,23 +2277,21 @@ static int setplane_internal(struct drm_plane *plane, | |||
2259 | uint32_t src_w, uint32_t src_h) | 2277 | uint32_t src_w, uint32_t src_h) |
2260 | { | 2278 | { |
2261 | struct drm_device *dev = plane->dev; | 2279 | struct drm_device *dev = plane->dev; |
2262 | struct drm_framebuffer *old_fb = NULL; | ||
2263 | int ret = 0; | 2280 | int ret = 0; |
2264 | unsigned int fb_width, fb_height; | 2281 | unsigned int fb_width, fb_height; |
2265 | int i; | 2282 | int i; |
2266 | 2283 | ||
2284 | drm_modeset_lock_all(dev); | ||
2267 | /* No fb means shut it down */ | 2285 | /* No fb means shut it down */ |
2268 | if (!fb) { | 2286 | if (!fb) { |
2269 | drm_modeset_lock_all(dev); | 2287 | plane->old_fb = plane->fb; |
2270 | old_fb = plane->fb; | ||
2271 | ret = plane->funcs->disable_plane(plane); | 2288 | ret = plane->funcs->disable_plane(plane); |
2272 | if (!ret) { | 2289 | if (!ret) { |
2273 | plane->crtc = NULL; | 2290 | plane->crtc = NULL; |
2274 | plane->fb = NULL; | 2291 | plane->fb = NULL; |
2275 | } else { | 2292 | } else { |
2276 | old_fb = NULL; | 2293 | plane->old_fb = NULL; |
2277 | } | 2294 | } |
2278 | drm_modeset_unlock_all(dev); | ||
2279 | goto out; | 2295 | goto out; |
2280 | } | 2296 | } |
2281 | 2297 | ||
@@ -2315,8 +2331,7 @@ static int setplane_internal(struct drm_plane *plane, | |||
2315 | goto out; | 2331 | goto out; |
2316 | } | 2332 | } |
2317 | 2333 | ||
2318 | drm_modeset_lock_all(dev); | 2334 | plane->old_fb = plane->fb; |
2319 | old_fb = plane->fb; | ||
2320 | ret = plane->funcs->update_plane(plane, crtc, fb, | 2335 | ret = plane->funcs->update_plane(plane, crtc, fb, |
2321 | crtc_x, crtc_y, crtc_w, crtc_h, | 2336 | crtc_x, crtc_y, crtc_w, crtc_h, |
2322 | src_x, src_y, src_w, src_h); | 2337 | src_x, src_y, src_w, src_h); |
@@ -2325,15 +2340,16 @@ static int setplane_internal(struct drm_plane *plane, | |||
2325 | plane->fb = fb; | 2340 | plane->fb = fb; |
2326 | fb = NULL; | 2341 | fb = NULL; |
2327 | } else { | 2342 | } else { |
2328 | old_fb = NULL; | 2343 | plane->old_fb = NULL; |
2329 | } | 2344 | } |
2330 | drm_modeset_unlock_all(dev); | ||
2331 | 2345 | ||
2332 | out: | 2346 | out: |
2333 | if (fb) | 2347 | if (fb) |
2334 | drm_framebuffer_unreference(fb); | 2348 | drm_framebuffer_unreference(fb); |
2335 | if (old_fb) | 2349 | if (plane->old_fb) |
2336 | drm_framebuffer_unreference(old_fb); | 2350 | drm_framebuffer_unreference(plane->old_fb); |
2351 | plane->old_fb = NULL; | ||
2352 | drm_modeset_unlock_all(dev); | ||
2337 | 2353 | ||
2338 | return ret; | 2354 | return ret; |
2339 | 2355 | ||
@@ -2440,7 +2456,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) | |||
2440 | * crtcs. Atomic modeset will have saner semantics ... | 2456 | * crtcs. Atomic modeset will have saner semantics ... |
2441 | */ | 2457 | */ |
2442 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) | 2458 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) |
2443 | tmp->old_fb = tmp->primary->fb; | 2459 | tmp->primary->old_fb = tmp->primary->fb; |
2444 | 2460 | ||
2445 | fb = set->fb; | 2461 | fb = set->fb; |
2446 | 2462 | ||
@@ -2453,8 +2469,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) { | 2469 | list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { |
2454 | if (tmp->primary->fb) | 2470 | if (tmp->primary->fb) |
2455 | drm_framebuffer_reference(tmp->primary->fb); | 2471 | drm_framebuffer_reference(tmp->primary->fb); |
2456 | if (tmp->old_fb) | 2472 | if (tmp->primary->old_fb) |
2457 | drm_framebuffer_unreference(tmp->old_fb); | 2473 | drm_framebuffer_unreference(tmp->primary->old_fb); |
2474 | tmp->primary->old_fb = NULL; | ||
2458 | } | 2475 | } |
2459 | 2476 | ||
2460 | return ret; | 2477 | return ret; |
@@ -2785,7 +2802,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, | |||
2785 | if (crtc->cursor) | 2802 | if (crtc->cursor) |
2786 | return drm_mode_cursor_universal(crtc, req, file_priv); | 2803 | return drm_mode_cursor_universal(crtc, req, file_priv); |
2787 | 2804 | ||
2788 | drm_modeset_lock(&crtc->mutex, NULL); | 2805 | drm_modeset_lock_crtc(crtc); |
2789 | if (req->flags & DRM_MODE_CURSOR_BO) { | 2806 | if (req->flags & DRM_MODE_CURSOR_BO) { |
2790 | if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { | 2807 | if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { |
2791 | ret = -ENXIO; | 2808 | ret = -ENXIO; |
@@ -2809,7 +2826,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, | |||
2809 | } | 2826 | } |
2810 | } | 2827 | } |
2811 | out: | 2828 | out: |
2812 | drm_modeset_unlock(&crtc->mutex); | 2829 | drm_modeset_unlock_crtc(crtc); |
2813 | 2830 | ||
2814 | return ret; | 2831 | return ret; |
2815 | 2832 | ||
@@ -3495,9 +3512,10 @@ EXPORT_SYMBOL(drm_property_create_enum); | |||
3495 | * @flags: flags specifying the property type | 3512 | * @flags: flags specifying the property type |
3496 | * @name: name of the property | 3513 | * @name: name of the property |
3497 | * @props: enumeration lists with property bitflags | 3514 | * @props: enumeration lists with property bitflags |
3498 | * @num_values: number of pre-defined values | 3515 | * @num_props: size of the @props array |
3516 | * @supported_bits: bitmask of all supported enumeration values | ||
3499 | * | 3517 | * |
3500 | * This creates a new generic drm property which can then be attached to a drm | 3518 | * 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 | 3519 | * object with drm_object_attach_property. The returned property object must be |
3502 | * freed with drm_property_destroy. | 3520 | * freed with drm_property_destroy. |
3503 | * | 3521 | * |
@@ -4529,7 +4547,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4529 | { | 4547 | { |
4530 | struct drm_mode_crtc_page_flip *page_flip = data; | 4548 | struct drm_mode_crtc_page_flip *page_flip = data; |
4531 | struct drm_crtc *crtc; | 4549 | struct drm_crtc *crtc; |
4532 | struct drm_framebuffer *fb = NULL, *old_fb = NULL; | 4550 | struct drm_framebuffer *fb = NULL; |
4533 | struct drm_pending_vblank_event *e = NULL; | 4551 | struct drm_pending_vblank_event *e = NULL; |
4534 | unsigned long flags; | 4552 | unsigned long flags; |
4535 | int ret = -EINVAL; | 4553 | int ret = -EINVAL; |
@@ -4545,7 +4563,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4545 | if (!crtc) | 4563 | if (!crtc) |
4546 | return -ENOENT; | 4564 | return -ENOENT; |
4547 | 4565 | ||
4548 | drm_modeset_lock(&crtc->mutex, NULL); | 4566 | drm_modeset_lock_crtc(crtc); |
4549 | if (crtc->primary->fb == NULL) { | 4567 | if (crtc->primary->fb == NULL) { |
4550 | /* The framebuffer is currently unbound, presumably | 4568 | /* The framebuffer is currently unbound, presumably |
4551 | * due to a hotplug event, that userspace has not | 4569 | * due to a hotplug event, that userspace has not |
@@ -4601,7 +4619,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4601 | (void (*) (struct drm_pending_event *)) kfree; | 4619 | (void (*) (struct drm_pending_event *)) kfree; |
4602 | } | 4620 | } |
4603 | 4621 | ||
4604 | old_fb = crtc->primary->fb; | 4622 | crtc->primary->old_fb = crtc->primary->fb; |
4605 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); | 4623 | ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); |
4606 | if (ret) { | 4624 | if (ret) { |
4607 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | 4625 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { |
@@ -4611,7 +4629,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4611 | kfree(e); | 4629 | kfree(e); |
4612 | } | 4630 | } |
4613 | /* Keep the old fb, don't unref it. */ | 4631 | /* Keep the old fb, don't unref it. */ |
4614 | old_fb = NULL; | 4632 | crtc->primary->old_fb = NULL; |
4615 | } else { | 4633 | } else { |
4616 | /* | 4634 | /* |
4617 | * Warn if the driver hasn't properly updated the crtc->fb | 4635 | * Warn if the driver hasn't properly updated the crtc->fb |
@@ -4627,9 +4645,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
4627 | out: | 4645 | out: |
4628 | if (fb) | 4646 | if (fb) |
4629 | drm_framebuffer_unreference(fb); | 4647 | drm_framebuffer_unreference(fb); |
4630 | if (old_fb) | 4648 | if (crtc->primary->old_fb) |
4631 | drm_framebuffer_unreference(old_fb); | 4649 | drm_framebuffer_unreference(crtc->primary->old_fb); |
4632 | drm_modeset_unlock(&crtc->mutex); | 4650 | crtc->primary->old_fb = NULL; |
4651 | drm_modeset_unlock_crtc(crtc); | ||
4633 | 4652 | ||
4634 | return ret; | 4653 | return ret; |
4635 | } | 4654 | } |
@@ -4645,9 +4664,14 @@ out: | |||
4645 | void drm_mode_config_reset(struct drm_device *dev) | 4664 | void drm_mode_config_reset(struct drm_device *dev) |
4646 | { | 4665 | { |
4647 | struct drm_crtc *crtc; | 4666 | struct drm_crtc *crtc; |
4667 | struct drm_plane *plane; | ||
4648 | struct drm_encoder *encoder; | 4668 | struct drm_encoder *encoder; |
4649 | struct drm_connector *connector; | 4669 | struct drm_connector *connector; |
4650 | 4670 | ||
4671 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) | ||
4672 | if (plane->funcs->reset) | ||
4673 | plane->funcs->reset(plane); | ||
4674 | |||
4651 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | 4675 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) |
4652 | if (crtc->funcs->reset) | 4676 | if (crtc->funcs->reset) |
4653 | crtc->funcs->reset(crtc); | 4677 | crtc->funcs->reset(crtc); |
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index ac3c2738db94..b3adf1445020 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -1772,7 +1772,7 @@ static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count) | |||
1772 | case DP_LINK_BW_5_4: | 1772 | case DP_LINK_BW_5_4: |
1773 | return 10 * dp_link_count; | 1773 | return 10 * dp_link_count; |
1774 | } | 1774 | } |
1775 | return 0; | 1775 | BUG(); |
1776 | } | 1776 | } |
1777 | 1777 | ||
1778 | /** | 1778 | /** |
@@ -2071,6 +2071,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) | |||
2071 | * drm_dp_mst_hpd_irq() - MST hotplug IRQ notify | 2071 | * drm_dp_mst_hpd_irq() - MST hotplug IRQ notify |
2072 | * @mgr: manager to notify irq for. | 2072 | * @mgr: manager to notify irq for. |
2073 | * @esi: 4 bytes from SINK_COUNT_ESI | 2073 | * @esi: 4 bytes from SINK_COUNT_ESI |
2074 | * @handled: whether the hpd interrupt was consumed or not | ||
2074 | * | 2075 | * |
2075 | * This should be called from the driver when it detects a short IRQ, | 2076 | * This should be called from the driver when it detects a short IRQ, |
2076 | * along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The | 2077 | * along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1dbf3bc4c6a3..f905c63c0f68 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -3433,10 +3433,10 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable); | |||
3433 | /** | 3433 | /** |
3434 | * drm_assign_hdmi_deep_color_info - detect whether monitor supports | 3434 | * drm_assign_hdmi_deep_color_info - detect whether monitor supports |
3435 | * hdmi deep color modes and update drm_display_info if so. | 3435 | * hdmi deep color modes and update drm_display_info if so. |
3436 | * | ||
3437 | * @edid: monitor EDID information | 3436 | * @edid: monitor EDID information |
3438 | * @info: Updated with maximum supported deep color bpc and color format | 3437 | * @info: Updated with maximum supported deep color bpc and color format |
3439 | * if deep color supported. | 3438 | * if deep color supported. |
3439 | * @connector: DRM connector, used only for debug output | ||
3440 | * | 3440 | * |
3441 | * Parse the CEA extension according to CEA-861-B. | 3441 | * Parse the CEA extension according to CEA-861-B. |
3442 | * Return true if HDMI deep color supported, false if not or unknown. | 3442 | * Return true if HDMI deep color supported, false if not or unknown. |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3144db9dc0f1..6019392b19cc 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -126,7 +126,7 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_ | |||
126 | 126 | ||
127 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); | 127 | WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); |
128 | if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { | 128 | if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { |
129 | temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector) * (fb_helper->connector_count + 1), GFP_KERNEL); | 129 | temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); |
130 | if (!temp) | 130 | if (!temp) |
131 | return -ENOMEM; | 131 | return -ENOMEM; |
132 | 132 | ||
@@ -171,60 +171,6 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, | |||
171 | } | 171 | } |
172 | EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); | 172 | EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); |
173 | 173 | ||
174 | static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) | ||
175 | { | ||
176 | struct drm_fb_helper_connector *fb_helper_conn; | ||
177 | int i; | ||
178 | |||
179 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
180 | struct drm_cmdline_mode *mode; | ||
181 | struct drm_connector *connector; | ||
182 | char *option = NULL; | ||
183 | |||
184 | fb_helper_conn = fb_helper->connector_info[i]; | ||
185 | connector = fb_helper_conn->connector; | ||
186 | mode = &fb_helper_conn->cmdline_mode; | ||
187 | |||
188 | /* do something on return - turn off connector maybe */ | ||
189 | if (fb_get_options(connector->name, &option)) | ||
190 | continue; | ||
191 | |||
192 | if (drm_mode_parse_command_line_for_connector(option, | ||
193 | connector, | ||
194 | mode)) { | ||
195 | if (mode->force) { | ||
196 | const char *s; | ||
197 | switch (mode->force) { | ||
198 | case DRM_FORCE_OFF: | ||
199 | s = "OFF"; | ||
200 | break; | ||
201 | case DRM_FORCE_ON_DIGITAL: | ||
202 | s = "ON - dig"; | ||
203 | break; | ||
204 | default: | ||
205 | case DRM_FORCE_ON: | ||
206 | s = "ON"; | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | DRM_INFO("forcing %s connector %s\n", | ||
211 | connector->name, s); | ||
212 | connector->force = mode->force; | ||
213 | } | ||
214 | |||
215 | DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", | ||
216 | connector->name, | ||
217 | mode->xres, mode->yres, | ||
218 | mode->refresh_specified ? mode->refresh : 60, | ||
219 | mode->rb ? " reduced blanking" : "", | ||
220 | mode->margins ? " with margins" : "", | ||
221 | mode->interlace ? " interlaced" : ""); | ||
222 | } | ||
223 | |||
224 | } | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) | 174 | static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) |
229 | { | 175 | { |
230 | uint16_t *r_base, *g_base, *b_base; | 176 | uint16_t *r_base, *g_base, *b_base; |
@@ -419,11 +365,11 @@ static bool drm_fb_helper_force_kernel_mode(void) | |||
419 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | 365 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) |
420 | continue; | 366 | continue; |
421 | 367 | ||
422 | /* NOTE: we use lockless flag below to avoid grabbing other | 368 | /* |
423 | * modeset locks. So just trylock the underlying mutex | 369 | * NOTE: Use trylock mode to avoid deadlocks and sleeping in |
424 | * directly: | 370 | * panic context. |
425 | */ | 371 | */ |
426 | if (!mutex_trylock(&dev->mode_config.mutex)) { | 372 | if (__drm_modeset_lock_all(dev, true) != 0) { |
427 | error = true; | 373 | error = true; |
428 | continue; | 374 | continue; |
429 | } | 375 | } |
@@ -432,7 +378,7 @@ static bool drm_fb_helper_force_kernel_mode(void) | |||
432 | if (ret) | 378 | if (ret) |
433 | error = true; | 379 | error = true; |
434 | 380 | ||
435 | mutex_unlock(&dev->mode_config.mutex); | 381 | drm_modeset_unlock_all(dev); |
436 | } | 382 | } |
437 | return error; | 383 | return error; |
438 | } | 384 | } |
@@ -1013,7 +959,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
1013 | struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; | 959 | struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; |
1014 | struct drm_cmdline_mode *cmdline_mode; | 960 | struct drm_cmdline_mode *cmdline_mode; |
1015 | 961 | ||
1016 | cmdline_mode = &fb_helper_conn->cmdline_mode; | 962 | cmdline_mode = &fb_helper_conn->connector->cmdline_mode; |
1017 | 963 | ||
1018 | if (cmdline_mode->bpp_specified) { | 964 | if (cmdline_mode->bpp_specified) { |
1019 | switch (cmdline_mode->bpp) { | 965 | switch (cmdline_mode->bpp) { |
@@ -1260,9 +1206,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode); | |||
1260 | 1206 | ||
1261 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) | 1207 | static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) |
1262 | { | 1208 | { |
1263 | struct drm_cmdline_mode *cmdline_mode; | 1209 | return fb_connector->connector->cmdline_mode.specified; |
1264 | cmdline_mode = &fb_connector->cmdline_mode; | ||
1265 | return cmdline_mode->specified; | ||
1266 | } | 1210 | } |
1267 | 1211 | ||
1268 | struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, | 1212 | struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, |
@@ -1272,7 +1216,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f | |||
1272 | struct drm_display_mode *mode = NULL; | 1216 | struct drm_display_mode *mode = NULL; |
1273 | bool prefer_non_interlace; | 1217 | bool prefer_non_interlace; |
1274 | 1218 | ||
1275 | cmdline_mode = &fb_helper_conn->cmdline_mode; | 1219 | cmdline_mode = &fb_helper_conn->connector->cmdline_mode; |
1276 | if (cmdline_mode->specified == false) | 1220 | if (cmdline_mode->specified == false) |
1277 | return mode; | 1221 | return mode; |
1278 | 1222 | ||
@@ -1657,8 +1601,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) | |||
1657 | struct drm_device *dev = fb_helper->dev; | 1601 | struct drm_device *dev = fb_helper->dev; |
1658 | int count = 0; | 1602 | int count = 0; |
1659 | 1603 | ||
1660 | drm_fb_helper_parse_command_line(fb_helper); | ||
1661 | |||
1662 | mutex_lock(&dev->mode_config.mutex); | 1604 | mutex_lock(&dev->mode_config.mutex); |
1663 | count = drm_fb_helper_probe_connector_modes(fb_helper, | 1605 | count = drm_fb_helper_probe_connector_modes(fb_helper, |
1664 | dev->mode_config.max_width, | 1606 | dev->mode_config.max_width, |
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 79d5221c6e41..6dbbb0fd54eb 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -464,6 +464,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
464 | if (drm_core_check_feature(dev, DRIVER_PRIME)) | 464 | if (drm_core_check_feature(dev, DRIVER_PRIME)) |
465 | drm_prime_destroy_file_private(&file_priv->prime); | 465 | drm_prime_destroy_file_private(&file_priv->prime); |
466 | 466 | ||
467 | WARN_ON(!list_empty(&file_priv->event_list)); | ||
468 | |||
467 | put_pid(file_priv->pid); | 469 | put_pid(file_priv->pid); |
468 | kfree(file_priv); | 470 | kfree(file_priv); |
469 | 471 | ||
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 08ba1209228e..5708c056fa1b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -720,6 +720,8 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp); | |||
720 | */ | 720 | */ |
721 | u32 drm_vblank_count(struct drm_device *dev, int crtc) | 721 | u32 drm_vblank_count(struct drm_device *dev, int crtc) |
722 | { | 722 | { |
723 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
724 | return 0; | ||
723 | return atomic_read(&dev->vblank[crtc].count); | 725 | return atomic_read(&dev->vblank[crtc].count); |
724 | } | 726 | } |
725 | EXPORT_SYMBOL(drm_vblank_count); | 727 | EXPORT_SYMBOL(drm_vblank_count); |
@@ -742,6 +744,9 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, | |||
742 | { | 744 | { |
743 | u32 cur_vblank; | 745 | u32 cur_vblank; |
744 | 746 | ||
747 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
748 | return 0; | ||
749 | |||
745 | /* Read timestamp from slot of _vblank_time ringbuffer | 750 | /* Read timestamp from slot of _vblank_time ringbuffer |
746 | * that corresponds to current vblank count. Retry if | 751 | * that corresponds to current vblank count. Retry if |
747 | * count has incremented during readout. This works like | 752 | * count has incremented during readout. This works like |
@@ -917,6 +922,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc) | |||
917 | unsigned long irqflags; | 922 | unsigned long irqflags; |
918 | int ret = 0; | 923 | int ret = 0; |
919 | 924 | ||
925 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
926 | return -EINVAL; | ||
927 | |||
920 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 928 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
921 | /* Going from 0->1 means we have to enable interrupts again */ | 929 | /* Going from 0->1 means we have to enable interrupts again */ |
922 | if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { | 930 | if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { |
@@ -965,6 +973,9 @@ void drm_vblank_put(struct drm_device *dev, int crtc) | |||
965 | { | 973 | { |
966 | BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0); | 974 | BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0); |
967 | 975 | ||
976 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
977 | return; | ||
978 | |||
968 | /* Last user schedules interrupt disable */ | 979 | /* Last user schedules interrupt disable */ |
969 | if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && | 980 | if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && |
970 | (drm_vblank_offdelay > 0)) | 981 | (drm_vblank_offdelay > 0)) |
@@ -989,6 +1000,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc) | |||
989 | EXPORT_SYMBOL(drm_crtc_vblank_put); | 1000 | EXPORT_SYMBOL(drm_crtc_vblank_put); |
990 | 1001 | ||
991 | /** | 1002 | /** |
1003 | * drm_wait_one_vblank - wait for one vblank | ||
1004 | * @dev: DRM device | ||
1005 | * @crtc: crtc index | ||
1006 | * | ||
1007 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. | ||
1008 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. | ||
1009 | * due to lack of driver support or because the crtc is off. | ||
1010 | */ | ||
1011 | void drm_wait_one_vblank(struct drm_device *dev, int crtc) | ||
1012 | { | ||
1013 | int ret; | ||
1014 | u32 last; | ||
1015 | |||
1016 | ret = drm_vblank_get(dev, crtc); | ||
1017 | if (WARN_ON(ret)) | ||
1018 | return; | ||
1019 | |||
1020 | last = drm_vblank_count(dev, crtc); | ||
1021 | |||
1022 | ret = wait_event_timeout(dev->vblank[crtc].queue, | ||
1023 | last != drm_vblank_count(dev, crtc), | ||
1024 | msecs_to_jiffies(100)); | ||
1025 | |||
1026 | WARN_ON(ret == 0); | ||
1027 | |||
1028 | drm_vblank_put(dev, crtc); | ||
1029 | } | ||
1030 | EXPORT_SYMBOL(drm_wait_one_vblank); | ||
1031 | |||
1032 | /** | ||
1033 | * drm_crtc_wait_one_vblank - wait for one vblank | ||
1034 | * @crtc: DRM crtc | ||
1035 | * | ||
1036 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. | ||
1037 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. | ||
1038 | * due to lack of driver support or because the crtc is off. | ||
1039 | */ | ||
1040 | void drm_crtc_wait_one_vblank(struct drm_crtc *crtc) | ||
1041 | { | ||
1042 | drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); | ||
1043 | } | ||
1044 | EXPORT_SYMBOL(drm_crtc_wait_one_vblank); | ||
1045 | |||
1046 | /** | ||
992 | * drm_vblank_off - disable vblank events on a CRTC | 1047 | * drm_vblank_off - disable vblank events on a CRTC |
993 | * @dev: DRM device | 1048 | * @dev: DRM device |
994 | * @crtc: CRTC in question | 1049 | * @crtc: CRTC in question |
@@ -1009,6 +1064,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) | |||
1009 | unsigned long irqflags; | 1064 | unsigned long irqflags; |
1010 | unsigned int seq; | 1065 | unsigned int seq; |
1011 | 1066 | ||
1067 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1068 | return; | ||
1069 | |||
1012 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1070 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
1013 | vblank_disable_and_save(dev, crtc); | 1071 | vblank_disable_and_save(dev, crtc); |
1014 | wake_up(&dev->vblank[crtc].queue); | 1072 | wake_up(&dev->vblank[crtc].queue); |
@@ -1068,6 +1126,9 @@ void drm_vblank_on(struct drm_device *dev, int crtc) | |||
1068 | { | 1126 | { |
1069 | unsigned long irqflags; | 1127 | unsigned long irqflags; |
1070 | 1128 | ||
1129 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1130 | return; | ||
1131 | |||
1071 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1132 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
1072 | /* re-enable interrupts if there's are users left */ | 1133 | /* re-enable interrupts if there's are users left */ |
1073 | if (atomic_read(&dev->vblank[crtc].refcount) != 0) | 1134 | if (atomic_read(&dev->vblank[crtc].refcount) != 0) |
@@ -1121,6 +1182,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | |||
1121 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ | 1182 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
1122 | if (!dev->num_crtcs) | 1183 | if (!dev->num_crtcs) |
1123 | return; | 1184 | return; |
1185 | |||
1186 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1187 | return; | ||
1188 | |||
1124 | /* | 1189 | /* |
1125 | * To avoid all the problems that might happen if interrupts | 1190 | * To avoid all the problems that might happen if interrupts |
1126 | * were enabled/disabled around or between these calls, we just | 1191 | * were enabled/disabled around or between these calls, we just |
@@ -1429,6 +1494,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1429 | if (!dev->num_crtcs) | 1494 | if (!dev->num_crtcs) |
1430 | return false; | 1495 | return false; |
1431 | 1496 | ||
1497 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1498 | return false; | ||
1499 | |||
1432 | /* Need timestamp lock to prevent concurrent execution with | 1500 | /* Need timestamp lock to prevent concurrent execution with |
1433 | * vblank enable/disable, as this would cause inconsistent | 1501 | * vblank enable/disable, as this would cause inconsistent |
1434 | * or corrupted timestamps and vblank counts. | 1502 | * or corrupted timestamps and vblank counts. |
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index bedf1894e17e..d1b7d2006529 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
@@ -1259,6 +1259,7 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev, | |||
1259 | if (!mode) | 1259 | if (!mode) |
1260 | return NULL; | 1260 | return NULL; |
1261 | 1261 | ||
1262 | mode->type |= DRM_MODE_TYPE_USERDEF; | ||
1262 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | 1263 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
1263 | return mode; | 1264 | return mode; |
1264 | } | 1265 | } |
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 0dc57d5ecd10..8749fc06570e 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c | |||
@@ -57,6 +57,212 @@ | |||
57 | 57 | ||
58 | 58 | ||
59 | /** | 59 | /** |
60 | * __drm_modeset_lock_all - internal helper to grab all modeset locks | ||
61 | * @dev: DRM device | ||
62 | * @trylock: trylock mode for atomic contexts | ||
63 | * | ||
64 | * This is a special version of drm_modeset_lock_all() which can also be used in | ||
65 | * atomic contexts. Then @trylock must be set to true. | ||
66 | * | ||
67 | * Returns: | ||
68 | * 0 on success or negative error code on failure. | ||
69 | */ | ||
70 | int __drm_modeset_lock_all(struct drm_device *dev, | ||
71 | bool trylock) | ||
72 | { | ||
73 | struct drm_mode_config *config = &dev->mode_config; | ||
74 | struct drm_modeset_acquire_ctx *ctx; | ||
75 | int ret; | ||
76 | |||
77 | ctx = kzalloc(sizeof(*ctx), | ||
78 | trylock ? GFP_ATOMIC : GFP_KERNEL); | ||
79 | if (!ctx) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | if (trylock) { | ||
83 | if (!mutex_trylock(&config->mutex)) | ||
84 | return -EBUSY; | ||
85 | } else { | ||
86 | mutex_lock(&config->mutex); | ||
87 | } | ||
88 | |||
89 | drm_modeset_acquire_init(ctx, 0); | ||
90 | ctx->trylock_only = trylock; | ||
91 | |||
92 | retry: | ||
93 | ret = drm_modeset_lock(&config->connection_mutex, ctx); | ||
94 | if (ret) | ||
95 | goto fail; | ||
96 | ret = drm_modeset_lock_all_crtcs(dev, ctx); | ||
97 | if (ret) | ||
98 | goto fail; | ||
99 | |||
100 | WARN_ON(config->acquire_ctx); | ||
101 | |||
102 | /* now we hold the locks, so now that it is safe, stash the | ||
103 | * ctx for drm_modeset_unlock_all(): | ||
104 | */ | ||
105 | config->acquire_ctx = ctx; | ||
106 | |||
107 | drm_warn_on_modeset_not_all_locked(dev); | ||
108 | |||
109 | return 0; | ||
110 | |||
111 | fail: | ||
112 | if (ret == -EDEADLK) { | ||
113 | drm_modeset_backoff(ctx); | ||
114 | goto retry; | ||
115 | } | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | EXPORT_SYMBOL(__drm_modeset_lock_all); | ||
120 | |||
121 | /** | ||
122 | * drm_modeset_lock_all - take all modeset locks | ||
123 | * @dev: drm device | ||
124 | * | ||
125 | * This function takes all modeset locks, suitable where a more fine-grained | ||
126 | * scheme isn't (yet) implemented. Locks must be dropped with | ||
127 | * drm_modeset_unlock_all. | ||
128 | */ | ||
129 | void drm_modeset_lock_all(struct drm_device *dev) | ||
130 | { | ||
131 | WARN_ON(__drm_modeset_lock_all(dev, false) != 0); | ||
132 | } | ||
133 | EXPORT_SYMBOL(drm_modeset_lock_all); | ||
134 | |||
135 | /** | ||
136 | * drm_modeset_unlock_all - drop all modeset locks | ||
137 | * @dev: device | ||
138 | * | ||
139 | * This function drop all modeset locks taken by drm_modeset_lock_all. | ||
140 | */ | ||
141 | void drm_modeset_unlock_all(struct drm_device *dev) | ||
142 | { | ||
143 | struct drm_mode_config *config = &dev->mode_config; | ||
144 | struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; | ||
145 | |||
146 | if (WARN_ON(!ctx)) | ||
147 | return; | ||
148 | |||
149 | config->acquire_ctx = NULL; | ||
150 | drm_modeset_drop_locks(ctx); | ||
151 | drm_modeset_acquire_fini(ctx); | ||
152 | |||
153 | kfree(ctx); | ||
154 | |||
155 | mutex_unlock(&dev->mode_config.mutex); | ||
156 | } | ||
157 | EXPORT_SYMBOL(drm_modeset_unlock_all); | ||
158 | |||
159 | /** | ||
160 | * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx | ||
161 | * @crtc: drm crtc | ||
162 | * | ||
163 | * This function locks the given crtc using a hidden acquire context. This is | ||
164 | * necessary so that drivers internally using the atomic interfaces can grab | ||
165 | * further locks with the lock acquire context. | ||
166 | */ | ||
167 | void drm_modeset_lock_crtc(struct drm_crtc *crtc) | ||
168 | { | ||
169 | struct drm_modeset_acquire_ctx *ctx; | ||
170 | int ret; | ||
171 | |||
172 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
173 | if (WARN_ON(!ctx)) | ||
174 | return; | ||
175 | |||
176 | drm_modeset_acquire_init(ctx, 0); | ||
177 | |||
178 | retry: | ||
179 | ret = drm_modeset_lock(&crtc->mutex, ctx); | ||
180 | if (ret) | ||
181 | goto fail; | ||
182 | |||
183 | WARN_ON(crtc->acquire_ctx); | ||
184 | |||
185 | /* now we hold the locks, so now that it is safe, stash the | ||
186 | * ctx for drm_modeset_unlock_crtc(): | ||
187 | */ | ||
188 | crtc->acquire_ctx = ctx; | ||
189 | |||
190 | return; | ||
191 | |||
192 | fail: | ||
193 | if (ret == -EDEADLK) { | ||
194 | drm_modeset_backoff(ctx); | ||
195 | goto retry; | ||
196 | } | ||
197 | } | ||
198 | EXPORT_SYMBOL(drm_modeset_lock_crtc); | ||
199 | |||
200 | /** | ||
201 | * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls | ||
202 | * @crtc: drm crtc | ||
203 | * | ||
204 | * Legacy ioctl operations like cursor updates or page flips only have per-crtc | ||
205 | * locking, and store the acquire ctx in the corresponding crtc. All other | ||
206 | * legacy operations take all locks and use a global acquire context. This | ||
207 | * function grabs the right one. | ||
208 | */ | ||
209 | struct drm_modeset_acquire_ctx * | ||
210 | drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) | ||
211 | { | ||
212 | if (crtc->acquire_ctx) | ||
213 | return crtc->acquire_ctx; | ||
214 | |||
215 | WARN_ON(!crtc->dev->mode_config.acquire_ctx); | ||
216 | |||
217 | return crtc->dev->mode_config.acquire_ctx; | ||
218 | } | ||
219 | EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); | ||
220 | |||
221 | /** | ||
222 | * drm_modeset_unlock_crtc - drop crtc lock | ||
223 | * @crtc: drm crtc | ||
224 | * | ||
225 | * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other | ||
226 | * locks acquired through the hidden context. | ||
227 | */ | ||
228 | void drm_modeset_unlock_crtc(struct drm_crtc *crtc) | ||
229 | { | ||
230 | struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx; | ||
231 | |||
232 | if (WARN_ON(!ctx)) | ||
233 | return; | ||
234 | |||
235 | crtc->acquire_ctx = NULL; | ||
236 | drm_modeset_drop_locks(ctx); | ||
237 | drm_modeset_acquire_fini(ctx); | ||
238 | |||
239 | kfree(ctx); | ||
240 | } | ||
241 | EXPORT_SYMBOL(drm_modeset_unlock_crtc); | ||
242 | |||
243 | /** | ||
244 | * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked | ||
245 | * @dev: device | ||
246 | * | ||
247 | * Useful as a debug assert. | ||
248 | */ | ||
249 | void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) | ||
250 | { | ||
251 | struct drm_crtc *crtc; | ||
252 | |||
253 | /* Locking is currently fubar in the panic handler. */ | ||
254 | if (oops_in_progress) | ||
255 | return; | ||
256 | |||
257 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
258 | WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); | ||
259 | |||
260 | WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); | ||
261 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
262 | } | ||
263 | EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); | ||
264 | |||
265 | /** | ||
60 | * drm_modeset_acquire_init - initialize acquire context | 266 | * drm_modeset_acquire_init - initialize acquire context |
61 | * @ctx: the acquire context | 267 | * @ctx: the acquire context |
62 | * @flags: for future | 268 | * @flags: for future |
@@ -108,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, | |||
108 | 314 | ||
109 | WARN_ON(ctx->contended); | 315 | WARN_ON(ctx->contended); |
110 | 316 | ||
111 | if (interruptible && slow) { | 317 | if (ctx->trylock_only) { |
318 | if (!ww_mutex_trylock(&lock->mutex)) | ||
319 | return -EBUSY; | ||
320 | else | ||
321 | return 0; | ||
322 | } else if (interruptible && slow) { | ||
112 | ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); | 323 | ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); |
113 | } else if (interruptible) { | 324 | } else if (interruptible) { |
114 | ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); | 325 | ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); |
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index db7d250f7ac7..6857e9ad6339 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c | |||
@@ -82,6 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector, | |||
82 | return; | 82 | return; |
83 | } | 83 | } |
84 | 84 | ||
85 | static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) | ||
86 | { | ||
87 | struct drm_display_mode *mode; | ||
88 | |||
89 | if (!connector->cmdline_mode.specified) | ||
90 | return 0; | ||
91 | |||
92 | mode = drm_mode_create_from_cmdline_mode(connector->dev, | ||
93 | &connector->cmdline_mode); | ||
94 | if (mode == NULL) | ||
95 | return 0; | ||
96 | |||
97 | drm_mode_probed_add(connector, mode); | ||
98 | return 1; | ||
99 | } | ||
100 | |||
85 | static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, | 101 | static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, |
86 | uint32_t maxX, uint32_t maxY, bool merge_type_bits) | 102 | uint32_t maxX, uint32_t maxY, bool merge_type_bits) |
87 | { | 103 | { |
@@ -141,6 +157,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect | |||
141 | 157 | ||
142 | if (count == 0 && connector->status == connector_status_connected) | 158 | if (count == 0 && connector->status == connector_status_connected) |
143 | count = drm_add_modes_noedid(connector, 1024, 768); | 159 | count = drm_add_modes_noedid(connector, 1024, 768); |
160 | count += drm_helper_probe_add_cmdline_mode(connector); | ||
144 | if (count == 0) | 161 | if (count == 0) |
145 | goto prune; | 162 | goto prune; |
146 | 163 | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 45f04dea0ac2..83485ab81ce8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c | |||
@@ -1483,11 +1483,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector, | |||
1483 | { | 1483 | { |
1484 | struct drm_device *dev = connector->dev; | 1484 | struct drm_device *dev = connector->dev; |
1485 | struct mga_device *mdev = (struct mga_device*)dev->dev_private; | 1485 | struct mga_device *mdev = (struct mga_device*)dev->dev_private; |
1486 | struct mga_fbdev *mfbdev = mdev->mfbdev; | ||
1487 | struct drm_fb_helper *fb_helper = &mfbdev->helper; | ||
1488 | struct drm_fb_helper_connector *fb_helper_conn = NULL; | ||
1489 | int bpp = 32; | 1486 | int bpp = 32; |
1490 | int i = 0; | ||
1491 | 1487 | ||
1492 | if (IS_G200_SE(mdev)) { | 1488 | if (IS_G200_SE(mdev)) { |
1493 | if (mdev->unique_rev_id == 0x01) { | 1489 | if (mdev->unique_rev_id == 0x01) { |
@@ -1537,21 +1533,14 @@ static int mga_vga_mode_valid(struct drm_connector *connector, | |||
1537 | } | 1533 | } |
1538 | 1534 | ||
1539 | /* Validate the mode input by the user */ | 1535 | /* Validate the mode input by the user */ |
1540 | for (i = 0; i < fb_helper->connector_count; i++) { | 1536 | if (connector->cmdline_mode.specified) { |
1541 | if (fb_helper->connector_info[i]->connector == connector) { | 1537 | if (connector->cmdline_mode.bpp_specified) |
1542 | /* Found the helper for this connector */ | 1538 | bpp = connector->cmdline_mode.bpp; |
1543 | fb_helper_conn = fb_helper->connector_info[i]; | ||
1544 | if (fb_helper_conn->cmdline_mode.specified) { | ||
1545 | if (fb_helper_conn->cmdline_mode.bpp_specified) { | ||
1546 | bpp = fb_helper_conn->cmdline_mode.bpp; | ||
1547 | } | ||
1548 | } | ||
1549 | } | ||
1550 | } | 1539 | } |
1551 | 1540 | ||
1552 | if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) { | 1541 | if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) { |
1553 | if (fb_helper_conn) | 1542 | if (connector->cmdline_mode.specified) |
1554 | fb_helper_conn->cmdline_mode.specified = false; | 1543 | connector->cmdline_mode.specified = false; |
1555 | return MODE_BAD; | 1544 | return MODE_BAD; |
1556 | } | 1545 | } |
1557 | 1546 | ||
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index e911b9c96e19..ccbe2ae22ac5 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | menuconfig FB | 5 | menuconfig FB |
6 | tristate "Support for frame buffer devices" | 6 | tristate "Support for frame buffer devices" |
7 | select FB_CMDLINE | ||
7 | ---help--- | 8 | ---help--- |
8 | The frame buffer device provides an abstraction for the graphics | 9 | The frame buffer device provides an abstraction for the graphics |
9 | hardware. It represents the frame buffer of some video hardware and | 10 | hardware. It represents the frame buffer of some video hardware and |
@@ -52,6 +53,9 @@ config FIRMWARE_EDID | |||
52 | combination with certain motherboards and monitors are known to | 53 | combination with certain motherboards and monitors are known to |
53 | suffer from this problem. | 54 | suffer from this problem. |
54 | 55 | ||
56 | config FB_CMDLINE | ||
57 | bool | ||
58 | |||
55 | config FB_DDC | 59 | config FB_DDC |
56 | tristate | 60 | tristate |
57 | depends on FB | 61 | depends on FB |
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile index fa306538dac2..67f28e20a892 100644 --- a/drivers/video/fbdev/core/Makefile +++ b/drivers/video/fbdev/core/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-y += fb_notify.o | 1 | obj-y += fb_notify.o |
2 | obj-$(CONFIG_FB_CMDLINE) += fb_cmdline.o | ||
2 | obj-$(CONFIG_FB) += fb.o | 3 | obj-$(CONFIG_FB) += fb.o |
3 | fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ | 4 | fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ |
4 | modedb.o fbcvt.o | 5 | modedb.o fbcvt.o |
diff --git a/drivers/video/fbdev/core/fb_cmdline.c b/drivers/video/fbdev/core/fb_cmdline.c new file mode 100644 index 000000000000..39509ccd92f1 --- /dev/null +++ b/drivers/video/fbdev/core/fb_cmdline.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/fb_cmdline.c | ||
3 | * | ||
4 | * Copyright (C) 2014 Intel Corp | ||
5 | * Copyright (C) 1994 Martin Schaller | ||
6 | * | ||
7 | * 2001 - Documented with DocBook | ||
8 | * - Brad Douglas <brad@neruo.com> | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General Public | ||
11 | * License. See the file COPYING in the main directory of this archive | ||
12 | * for more details. | ||
13 | * | ||
14 | * Authors: | ||
15 | * Vetter <danie.vetter@ffwll.ch> | ||
16 | */ | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/fb.h> | ||
19 | |||
20 | static char *video_options[FB_MAX] __read_mostly; | ||
21 | static int ofonly __read_mostly; | ||
22 | |||
23 | const char *fb_mode_option; | ||
24 | EXPORT_SYMBOL_GPL(fb_mode_option); | ||
25 | |||
26 | /** | ||
27 | * fb_get_options - get kernel boot parameters | ||
28 | * @name: framebuffer name as it would appear in | ||
29 | * the boot parameter line | ||
30 | * (video=<name>:<options>) | ||
31 | * @option: the option will be stored here | ||
32 | * | ||
33 | * NOTE: Needed to maintain backwards compatibility | ||
34 | */ | ||
35 | int fb_get_options(const char *name, char **option) | ||
36 | { | ||
37 | char *opt, *options = NULL; | ||
38 | int retval = 0; | ||
39 | int name_len = strlen(name), i; | ||
40 | |||
41 | if (name_len && ofonly && strncmp(name, "offb", 4)) | ||
42 | retval = 1; | ||
43 | |||
44 | if (name_len && !retval) { | ||
45 | for (i = 0; i < FB_MAX; i++) { | ||
46 | if (video_options[i] == NULL) | ||
47 | continue; | ||
48 | if (!video_options[i][0]) | ||
49 | continue; | ||
50 | opt = video_options[i]; | ||
51 | if (!strncmp(name, opt, name_len) && | ||
52 | opt[name_len] == ':') | ||
53 | options = opt + name_len + 1; | ||
54 | } | ||
55 | } | ||
56 | /* No match, pass global option */ | ||
57 | if (!options && option && fb_mode_option) | ||
58 | options = kstrdup(fb_mode_option, GFP_KERNEL); | ||
59 | if (options && !strncmp(options, "off", 3)) | ||
60 | retval = 1; | ||
61 | |||
62 | if (option) | ||
63 | *option = options; | ||
64 | |||
65 | return retval; | ||
66 | } | ||
67 | EXPORT_SYMBOL(fb_get_options); | ||
68 | |||
69 | /** | ||
70 | * video_setup - process command line options | ||
71 | * @options: string of options | ||
72 | * | ||
73 | * Process command line options for frame buffer subsystem. | ||
74 | * | ||
75 | * NOTE: This function is a __setup and __init function. | ||
76 | * It only stores the options. Drivers have to call | ||
77 | * fb_get_options() as necessary. | ||
78 | * | ||
79 | * Returns zero. | ||
80 | * | ||
81 | */ | ||
82 | static int __init video_setup(char *options) | ||
83 | { | ||
84 | int i, global = 0; | ||
85 | |||
86 | if (!options || !*options) | ||
87 | global = 1; | ||
88 | |||
89 | if (!global && !strncmp(options, "ofonly", 6)) { | ||
90 | ofonly = 1; | ||
91 | global = 1; | ||
92 | } | ||
93 | |||
94 | if (!global && !strchr(options, ':')) { | ||
95 | fb_mode_option = options; | ||
96 | global = 1; | ||
97 | } | ||
98 | |||
99 | if (!global) { | ||
100 | for (i = 0; i < FB_MAX; i++) { | ||
101 | if (video_options[i] == NULL) { | ||
102 | video_options[i] = options; | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | return 1; | ||
109 | } | ||
110 | __setup("video=", video_setup); | ||
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index b5e85f6c1c26..0705d8883ede 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c | |||
@@ -1908,96 +1908,4 @@ int fb_new_modelist(struct fb_info *info) | |||
1908 | return err; | 1908 | return err; |
1909 | } | 1909 | } |
1910 | 1910 | ||
1911 | static char *video_options[FB_MAX] __read_mostly; | ||
1912 | static int ofonly __read_mostly; | ||
1913 | |||
1914 | /** | ||
1915 | * fb_get_options - get kernel boot parameters | ||
1916 | * @name: framebuffer name as it would appear in | ||
1917 | * the boot parameter line | ||
1918 | * (video=<name>:<options>) | ||
1919 | * @option: the option will be stored here | ||
1920 | * | ||
1921 | * NOTE: Needed to maintain backwards compatibility | ||
1922 | */ | ||
1923 | int fb_get_options(const char *name, char **option) | ||
1924 | { | ||
1925 | char *opt, *options = NULL; | ||
1926 | int retval = 0; | ||
1927 | int name_len = strlen(name), i; | ||
1928 | |||
1929 | if (name_len && ofonly && strncmp(name, "offb", 4)) | ||
1930 | retval = 1; | ||
1931 | |||
1932 | if (name_len && !retval) { | ||
1933 | for (i = 0; i < FB_MAX; i++) { | ||
1934 | if (video_options[i] == NULL) | ||
1935 | continue; | ||
1936 | if (!video_options[i][0]) | ||
1937 | continue; | ||
1938 | opt = video_options[i]; | ||
1939 | if (!strncmp(name, opt, name_len) && | ||
1940 | opt[name_len] == ':') | ||
1941 | options = opt + name_len + 1; | ||
1942 | } | ||
1943 | } | ||
1944 | /* No match, pass global option */ | ||
1945 | if (!options && option && fb_mode_option) | ||
1946 | options = kstrdup(fb_mode_option, GFP_KERNEL); | ||
1947 | if (options && !strncmp(options, "off", 3)) | ||
1948 | retval = 1; | ||
1949 | |||
1950 | if (option) | ||
1951 | *option = options; | ||
1952 | |||
1953 | return retval; | ||
1954 | } | ||
1955 | EXPORT_SYMBOL(fb_get_options); | ||
1956 | |||
1957 | #ifndef MODULE | ||
1958 | /** | ||
1959 | * video_setup - process command line options | ||
1960 | * @options: string of options | ||
1961 | * | ||
1962 | * Process command line options for frame buffer subsystem. | ||
1963 | * | ||
1964 | * NOTE: This function is a __setup and __init function. | ||
1965 | * It only stores the options. Drivers have to call | ||
1966 | * fb_get_options() as necessary. | ||
1967 | * | ||
1968 | * Returns zero. | ||
1969 | * | ||
1970 | */ | ||
1971 | static int __init video_setup(char *options) | ||
1972 | { | ||
1973 | int i, global = 0; | ||
1974 | |||
1975 | if (!options || !*options) | ||
1976 | global = 1; | ||
1977 | |||
1978 | if (!global && !strncmp(options, "ofonly", 6)) { | ||
1979 | ofonly = 1; | ||
1980 | global = 1; | ||
1981 | } | ||
1982 | |||
1983 | if (!global && !strchr(options, ':')) { | ||
1984 | fb_mode_option = options; | ||
1985 | global = 1; | ||
1986 | } | ||
1987 | |||
1988 | if (!global) { | ||
1989 | for (i = 0; i < FB_MAX; i++) { | ||
1990 | if (video_options[i] == NULL) { | ||
1991 | video_options[i] = options; | ||
1992 | break; | ||
1993 | } | ||
1994 | |||
1995 | } | ||
1996 | } | ||
1997 | |||
1998 | return 1; | ||
1999 | } | ||
2000 | __setup("video=", video_setup); | ||
2001 | #endif | ||
2002 | |||
2003 | MODULE_LICENSE("GPL"); | 1911 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index a9a907c440d7..388f7971494b 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c | |||
@@ -29,9 +29,6 @@ | |||
29 | #define DPRINTK(fmt, args...) | 29 | #define DPRINTK(fmt, args...) |
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | const char *fb_mode_option; | ||
33 | EXPORT_SYMBOL_GPL(fb_mode_option); | ||
34 | |||
35 | /* | 32 | /* |
36 | * Standard video mode definitions (taken from XFree86) | 33 | * Standard video mode definitions (taken from XFree86) |
37 | */ | 34 | */ |