aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-01-20 16:44:58 -0500
committerDave Airlie <airlied@redhat.com>2013-01-20 16:44:58 -0500
commit735dc0d1e29329ff34ec97f66e130cce481c9607 (patch)
treecf946856ff1defac833e601a3e4a4d8e841ee73e /include
parentbac4b7c3b5c0660c08dc4949fe40e08e20364ee3 (diff)
parent20c60c35de3285222b3476c3445c66bedf0c449c (diff)
Merge branch 'drm-kms-locking' of git://people.freedesktop.org/~danvet/drm-intel into drm-next
The aim of this locking rework is that ioctls which a compositor should be might call for every frame (set_cursor, page_flip, addfb, rmfb and getfb/create_handle) should not be able to block on kms background activities like output detection. And since each EDID read takes about 25ms (in the best case), that always means we'll drop at least one frame. The solution is to add per-crtc locking for these ioctls, and restrict background activities to only use the global lock. Change-the-world type of events (modeset, dpms, ...) need to grab all locks. Two tricky parts arose in the conversion: - A lot of current code assumes that a kms fb object can't disappear while holding the global lock, since the current code serializes fb destruction with it. Hence proper lifetime management using the already created refcounting for fbs need to be instantiated for all ioctls and interfaces/users. - The rmfb ioctl removes the to-be-deleted fb from all active users. But unconditionally taking the global kms lock to do so introduces an unacceptable potential stall point. And obviously changing the userspace abi isn't on the table, either. Hence this conversion opportunistically checks whether the rmfb ioctl holds the very last reference, which guarantees that the fb isn't in active use on any crtc or plane (thanks to the conversion to the new lifetime rules using proper refcounting). Only if this is not the case will the code go through the slowpath and grab all modeset locks. Sane compositors will never hit this path and so avoid the stall, but userspace relying on these semantics will also not break. All these cases are exercised by the newly added subtests for the i-g-t kms_flip, tested on a machine where a full detect cycle takes around 100 ms. It works, and no frames are dropped any more with these patches applied. kms_flip also contains a special case to exercise the above-describe rmfb slowpath. * 'drm-kms-locking' of git://people.freedesktop.org/~danvet/drm-intel: (335 commits) drm/fb_helper: check whether fbcon is bound drm/doc: updates for new framebuffer lifetime rules drm: don't hold crtc mutexes for connector ->detect callbacks drm: only grab the crtc lock for pageflips drm: optimize drm_framebuffer_remove drm/vmwgfx: add proper framebuffer refcounting drm/i915: dump refcount into framebuffer debugfs file drm: refcounting for crtc framebuffers drm: refcounting for sprite framebuffers drm: fb refcounting for dirtyfb_ioctl drm: don't take modeset locks in getfb ioctl drm: push modeset_lock_all into ->fb_create driver callbacks drm: nest modeset locks within fpriv->fbs_lock drm: reference framebuffers which are on the idr drm: revamp framebuffer cleanup interfaces drm: create drm_framebuffer_lookup drm: revamp locking around fb creation/destruction drm: only take the crtc lock for ->cursor_move drm: only take the crtc lock for ->cursor_set drm: add per-crtc locks ...
Diffstat (limited to 'include')
-rw-r--r--include/drm/drmP.h13
-rw-r--r--include/drm/drm_crtc.h30
-rw-r--r--include/drm/drm_mm.h2
-rw-r--r--include/linux/audit.h4
-rw-r--r--include/linux/compaction.h4
-rw-r--r--include/linux/cpu_rmap.h13
-rw-r--r--include/linux/cpuidle.h2
-rw-r--r--include/linux/init.h20
-rw-r--r--include/linux/interrupt.h5
-rw-r--r--include/linux/lockdep.h3
-rw-r--r--include/linux/mm.h1
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/linux/rbtree_augmented.h14
-rw-r--r--include/linux/rwsem.h9
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/sound/cs4271.h2
-rw-r--r--include/sound/soc.h10
-rw-r--r--include/target/target_core_base.h1
-rw-r--r--include/uapi/linux/audit.h2
19 files changed, 90 insertions, 49 deletions
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index fad21c927a38..e74731c1a912 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -446,7 +446,15 @@ struct drm_file {
446 int is_master; /* this file private is a master for a minor */ 446 int is_master; /* this file private is a master for a minor */
447 struct drm_master *master; /* master this node is currently associated with 447 struct drm_master *master; /* master this node is currently associated with
448 N.B. not always minor->master */ 448 N.B. not always minor->master */
449
450 /**
451 * fbs - List of framebuffers associated with this file.
452 *
453 * Protected by fbs_lock. Note that the fbs list holds a reference on
454 * the fb object to prevent it from untimely disappearing.
455 */
449 struct list_head fbs; 456 struct list_head fbs;
457 struct mutex fbs_lock;
450 458
451 wait_queue_head_t event_wait; 459 wait_queue_head_t event_wait;
452 struct list_head event_list; 460 struct list_head event_list;
@@ -1276,6 +1284,11 @@ static inline int drm_device_is_unplugged(struct drm_device *dev)
1276 return ret; 1284 return ret;
1277} 1285}
1278 1286
1287static inline bool drm_modeset_is_locked(struct drm_device *dev)
1288{
1289 return mutex_is_locked(&dev->mode_config.mutex);
1290}
1291
1279/******************************************************************/ 1292/******************************************************************/
1280/** \name Internal function definitions */ 1293/** \name Internal function definitions */
1281/*@{*/ 1294/*@{*/
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 00d78b5161c0..66b2732f175a 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -254,6 +254,10 @@ struct drm_framebuffer {
254 * userspace perspective. 254 * userspace perspective.
255 */ 255 */
256 struct kref refcount; 256 struct kref refcount;
257 /*
258 * Place on the dev->mode_config.fb_list, access protected by
259 * dev->mode_config.fb_lock.
260 */
257 struct list_head head; 261 struct list_head head;
258 struct drm_mode_object base; 262 struct drm_mode_object base;
259 const struct drm_framebuffer_funcs *funcs; 263 const struct drm_framebuffer_funcs *funcs;
@@ -390,6 +394,15 @@ struct drm_crtc {
390 struct drm_device *dev; 394 struct drm_device *dev;
391 struct list_head head; 395 struct list_head head;
392 396
397 /**
398 * crtc mutex
399 *
400 * This provides a read lock for the overall crtc state (mode, dpms
401 * state, ...) and a write lock for everything which can be update
402 * without a full modeset (fb, cursor data, ...)
403 */
404 struct mutex mutex;
405
393 struct drm_mode_object base; 406 struct drm_mode_object base;
394 407
395 /* framebuffer the connector is currently bound to */ 408 /* framebuffer the connector is currently bound to */
@@ -771,8 +784,18 @@ struct drm_mode_config {
771 struct mutex idr_mutex; /* for IDR management */ 784 struct mutex idr_mutex; /* for IDR management */
772 struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ 785 struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
773 /* this is limited to one for now */ 786 /* this is limited to one for now */
787
788
789 /**
790 * fb_lock - mutex to protect fb state
791 *
792 * Besides the global fb list his also protects the fbs list in the
793 * file_priv
794 */
795 struct mutex fb_lock;
774 int num_fb; 796 int num_fb;
775 struct list_head fb_list; 797 struct list_head fb_list;
798
776 int num_connector; 799 int num_connector;
777 struct list_head connector_list; 800 struct list_head connector_list;
778 int num_encoder; 801 int num_encoder;
@@ -842,6 +865,9 @@ struct drm_prop_enum_list {
842 char *name; 865 char *name;
843}; 866};
844 867
868extern void drm_modeset_lock_all(struct drm_device *dev);
869extern void drm_modeset_unlock_all(struct drm_device *dev);
870
845extern int drm_crtc_init(struct drm_device *dev, 871extern int drm_crtc_init(struct drm_device *dev,
846 struct drm_crtc *crtc, 872 struct drm_crtc *crtc,
847 const struct drm_crtc_funcs *funcs); 873 const struct drm_crtc_funcs *funcs);
@@ -932,10 +958,13 @@ extern void drm_framebuffer_set_object(struct drm_device *dev,
932extern int drm_framebuffer_init(struct drm_device *dev, 958extern int drm_framebuffer_init(struct drm_device *dev,
933 struct drm_framebuffer *fb, 959 struct drm_framebuffer *fb,
934 const struct drm_framebuffer_funcs *funcs); 960 const struct drm_framebuffer_funcs *funcs);
961extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
962 uint32_t id);
935extern void drm_framebuffer_unreference(struct drm_framebuffer *fb); 963extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
936extern void drm_framebuffer_reference(struct drm_framebuffer *fb); 964extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
937extern void drm_framebuffer_remove(struct drm_framebuffer *fb); 965extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
938extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); 966extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
967extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb);
939extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); 968extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
940extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); 969extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
941extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); 970extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY);
@@ -985,6 +1014,7 @@ extern int drm_mode_getcrtc(struct drm_device *dev,
985 void *data, struct drm_file *file_priv); 1014 void *data, struct drm_file *file_priv);
986extern int drm_mode_getconnector(struct drm_device *dev, 1015extern int drm_mode_getconnector(struct drm_device *dev,
987 void *data, struct drm_file *file_priv); 1016 void *data, struct drm_file *file_priv);
1017extern int drm_mode_set_config_internal(struct drm_mode_set *set);
988extern int drm_mode_setcrtc(struct drm_device *dev, 1018extern int drm_mode_setcrtc(struct drm_device *dev,
989 void *data, struct drm_file *file_priv); 1019 void *data, struct drm_file *file_priv);
990extern int drm_mode_getplane(struct drm_device *dev, 1020extern int drm_mode_getplane(struct drm_device *dev,
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 9b991f91d81b..88591ef8fa24 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -70,7 +70,7 @@ struct drm_mm {
70 unsigned long scan_color; 70 unsigned long scan_color;
71 unsigned long scan_size; 71 unsigned long scan_size;
72 unsigned long scan_hit_start; 72 unsigned long scan_hit_start;
73 unsigned scan_hit_size; 73 unsigned long scan_hit_end;
74 unsigned scanned_blocks; 74 unsigned scanned_blocks;
75 unsigned long scan_start; 75 unsigned long scan_start;
76 unsigned long scan_end; 76 unsigned long scan_end;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index bce729afbcf9..5a6d718adf34 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -24,6 +24,7 @@
24#define _LINUX_AUDIT_H_ 24#define _LINUX_AUDIT_H_
25 25