diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-08-20 04:13:36 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-09-06 18:04:11 -0400 |
commit | e58f637bb96d5a0ae0919b9998b891d1ba7e47c9 (patch) | |
tree | 6c6e7d588c284f5fafce4782aad66e29f62359c9 /drivers/gpu | |
parent | 54bfe496cec7586f76f713a277435dd3ac6fd4c4 (diff) |
drm/kms: Add a module parameter to disable polling
Polling for a VGA device on an old system can be quite expensive,
causing latencies on the order of 600ms. As we hold the mode mutex for
this time and also need the same mutex to move the cursor, we trigger a
user-visible stall.
The real solution would involve improving the granulatity of the
locking and so perhaps performing some of the probing not under the lock
or some other updates can be done under different locks. Also reducing the
cost of probing for a non-existent monitor would be worthwhile. However,
exposing a parameter to disable polling is a simple workaround in the
meantime.
In order to accommodate users turning polling on and off at runtime, the
polling is potentially re-enabled on every probe. This is coupled to
the user calling xrandr, which seems to be a vaild time to reset the
polling timeout since the information on the connection has just been
updated. (The presumption being that all connections are probed in a
single xrandr pass, which is currently valid.)
References:
Bug 29536 - 2.6.35 causes ~600ms latency every 10s
https://bugs.freedesktop.org/show_bug.cgi?id=29536
Bug 16265 - Why is kslowd accumulating so much CPU time?
https://bugzilla.kernel.org/show_bug.cgi?id=16265
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reported-and-tested-by: Bruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 7e31d4348340..06fc0bccaff7 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -34,6 +34,9 @@ | |||
34 | #include "drm_crtc_helper.h" | 34 | #include "drm_crtc_helper.h" |
35 | #include "drm_fb_helper.h" | 35 | #include "drm_fb_helper.h" |
36 | 36 | ||
37 | static bool drm_kms_helper_poll = true; | ||
38 | module_param_named(poll, drm_kms_helper_poll, bool, 0600); | ||
39 | |||
37 | static void drm_mode_validate_flag(struct drm_connector *connector, | 40 | static void drm_mode_validate_flag(struct drm_connector *connector, |
38 | int flags) | 41 | int flags) |
39 | { | 42 | { |
@@ -99,8 +102,10 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, | |||
99 | connector->status = connector_status_disconnected; | 102 | connector->status = connector_status_disconnected; |
100 | if (connector->funcs->force) | 103 | if (connector->funcs->force) |
101 | connector->funcs->force(connector); | 104 | connector->funcs->force(connector); |
102 | } else | 105 | } else { |
103 | connector->status = connector->funcs->detect(connector); | 106 | connector->status = connector->funcs->detect(connector); |
107 | drm_helper_hpd_irq_event(dev); | ||
108 | } | ||
104 | 109 | ||
105 | if (connector->status == connector_status_disconnected) { | 110 | if (connector->status == connector_status_disconnected) { |
106 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", | 111 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", |
@@ -840,6 +845,9 @@ static void output_poll_execute(struct work_struct *work) | |||
840 | enum drm_connector_status old_status, status; | 845 | enum drm_connector_status old_status, status; |
841 | bool repoll = false, changed = false; | 846 | bool repoll = false, changed = false; |
842 | 847 | ||
848 | if (!drm_kms_helper_poll) | ||
849 | return; | ||
850 | |||
843 | mutex_lock(&dev->mode_config.mutex); | 851 | mutex_lock(&dev->mode_config.mutex); |
844 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 852 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
845 | 853 | ||
@@ -890,6 +898,9 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) | |||
890 | bool poll = false; | 898 | bool poll = false; |
891 | struct drm_connector *connector; | 899 | struct drm_connector *connector; |
892 | 900 | ||
901 | if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) | ||
902 | return; | ||
903 | |||
893 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 904 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
894 | if (connector->polled) | 905 | if (connector->polled) |
895 | poll = true; | 906 | poll = true; |
@@ -919,8 +930,10 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) | |||
919 | { | 930 | { |
920 | if (!dev->mode_config.poll_enabled) | 931 | if (!dev->mode_config.poll_enabled) |
921 | return; | 932 | return; |
933 | |||
922 | /* kill timer and schedule immediate execution, this doesn't block */ | 934 | /* kill timer and schedule immediate execution, this doesn't block */ |
923 | cancel_delayed_work(&dev->mode_config.output_poll_work); | 935 | cancel_delayed_work(&dev->mode_config.output_poll_work); |
924 | queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); | 936 | if (drm_kms_helper_poll) |
937 | queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); | ||
925 | } | 938 | } |
926 | EXPORT_SYMBOL(drm_helper_hpd_irq_event); | 939 | EXPORT_SYMBOL(drm_helper_hpd_irq_event); |