Skip to content

Commit

Permalink
drm: convert crtc and connection_mutex to ww_mutex (v5)
Browse files Browse the repository at this point in the history
For atomic, it will be quite necessary to not need to care so much
about locking order.  And 'state' gives us a convenient place to stash a
ww_ctx for any sort of update that needs to grab multiple crtc locks.

Because we will want to eventually make locking even more fine grained
(giving locks to planes, connectors, etc), split out drm_modeset_lock
and drm_modeset_acquire_ctx to track acquired locks.

Atomic will use this to keep track of which locks have been acquired
in a transaction.

v1: original
v2: remove a few things not needed until atomic, for now
v3: update for v3 of connection_mutex patch..
v4: squash in docbook
v5: doc tweaks/fixes

Signed-off-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Rob Clark authored and Dave Airlie committed Jun 4, 2014
1 parent 4f71d0c commit 51fd371
Show file tree
Hide file tree
Showing 21 changed files with 531 additions and 87 deletions.
6 changes: 6 additions & 0 deletions Documentation/DocBook/drm.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,12 @@ void intel_crt_init(struct drm_device *dev)
<title>KMS API Functions</title>
!Edrivers/gpu/drm/drm_crtc.c
</sect2>
<sect2>
<title>KMS Locking</title>
!Pdrivers/gpu/drm/drm_modeset_lock.c kms locking
!Iinclude/drm/drm_modeset_lock.h
!Edrivers/gpu/drm/drm_modeset_lock.c
</sect2>
</sect1>

<!-- Internals: kms helper functions -->
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
drm_trace_points.o drm_global.o drm_prime.o \
drm_rect.o drm_vma_manager.o drm_flip_work.o
drm_rect.o drm_vma_manager.o drm_flip_work.o \
drm_modeset_lock.o

drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
Expand Down
85 changes: 63 additions & 22 deletions drivers/gpu/drm/drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_lock.h>

#include "drm_crtc_internal.h"

Expand All @@ -50,14 +51,42 @@
*/
void drm_modeset_lock_all(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx;
int ret;

mutex_lock(&dev->mode_config.mutex);
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (WARN_ON(!ctx))
return;

mutex_lock(&dev->mode_config.connection_mutex);
mutex_lock(&config->mutex);

list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
drm_modeset_acquire_init(ctx, 0);

retry:
ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret)
goto fail;
ret = drm_modeset_lock_all_crtcs(dev, ctx);
if (ret)
goto fail;

WARN_ON(config->acquire_ctx);

/* now we hold the locks, so now that it is safe, stash the
* ctx for drm_modeset_unlock_all():
*/
config->acquire_ctx = ctx;

drm_warn_on_modeset_not_all_locked(dev);

return;

fail:
if (ret == -EDEADLK) {
drm_modeset_backoff(ctx);
goto retry;
}
}
EXPORT_SYMBOL(drm_modeset_lock_all);

Expand All @@ -69,12 +98,17 @@ EXPORT_SYMBOL(drm_modeset_lock_all);
*/
void drm_modeset_unlock_all(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;

list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
mutex_unlock(&crtc->mutex);
if (WARN_ON(!ctx))
return;

config->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);

mutex_unlock(&dev->mode_config.connection_mutex);
kfree(ctx);

mutex_unlock(&dev->mode_config.mutex);
}
Expand All @@ -95,9 +129,9 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
return;

list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!mutex_is_locked(&crtc->mutex));
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));

WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex));
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
}
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
Expand Down Expand Up @@ -671,6 +705,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
}
EXPORT_SYMBOL(drm_framebuffer_remove);

DEFINE_WW_CLASS(crtc_ww_class);

/**
* drm_crtc_init_with_planes - Initialise a new CRTC object with
* specified primary and cursor planes.
Expand All @@ -690,24 +726,26 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
void *cursor,
const struct drm_crtc_funcs *funcs)
{
struct drm_mode_config *config = &dev->mode_config;
int ret;

crtc->dev = dev;
crtc->funcs = funcs;
crtc->invert_dimensions = false;

drm_modeset_lock_all(dev);
mutex_init(&crtc->mutex);
mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
drm_modeset_lock_init(&crtc->mutex);
/* dropped by _unlock_all(): */
drm_modeset_lock(&crtc->mutex, config->acquire_ctx);

ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
if (ret)
goto out;

crtc->base.properties = &crtc->properties;

list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
dev->mode_config.num_crtc++;
list_add_tail(&crtc->head, &config->crtc_list);
config->num_crtc++;

crtc->primary = primary;
if (primary)
Expand Down Expand Up @@ -735,6 +773,8 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
kfree(crtc->gamma_store);
crtc->gamma_store = NULL;

drm_modeset_lock_fini(&crtc->mutex);

drm_mode_object_put(dev, &crtc->base);
list_del(&crtc->head);
dev->mode_config.num_crtc--;
Expand Down Expand Up @@ -1798,7 +1838,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);

mutex_lock(&dev->mode_config.mutex);
mutex_lock(&dev->mode_config.connection_mutex);
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);

connector = drm_connector_find(dev, out_resp->connector_id);
if (!connector) {
Expand Down Expand Up @@ -1897,7 +1937,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
out_resp->count_encoders = encoders_count;

out:
mutex_unlock(&dev->mode_config.connection_mutex);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
mutex_unlock(&dev->mode_config.mutex);

return ret;
Expand Down Expand Up @@ -2481,7 +2521,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
return -ENOENT;
}

mutex_lock(&crtc->mutex);
drm_modeset_lock(&crtc->mutex, NULL);
if (req->flags & DRM_MODE_CURSOR_BO) {
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
ret = -ENXIO;
Expand All @@ -2505,7 +2545,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
}
}
out:
mutex_unlock(&crtc->mutex);
drm_modeset_unlock(&crtc->mutex);

return ret;

Expand Down Expand Up @@ -4198,7 +4238,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if (!crtc)
return -ENOENT;

mutex_lock(&crtc->mutex);
drm_modeset_lock(&crtc->mutex, NULL);
if (crtc->primary->fb == NULL) {
/* The framebuffer is currently unbound, presumably
* due to a hotplug event, that userspace has not
Expand Down Expand Up @@ -4282,7 +4322,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
drm_framebuffer_unreference(fb);
if (old_fb)
drm_framebuffer_unreference(old_fb);
mutex_unlock(&crtc->mutex);
drm_modeset_unlock(&crtc->mutex);

return ret;
}
Expand Down Expand Up @@ -4647,7 +4687,7 @@ EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
void drm_mode_config_init(struct drm_device *dev)
{
mutex_init(&dev->mode_config.mutex);
mutex_init(&dev->mode_config.connection_mutex);
drm_modeset_lock_init(&dev->mode_config.connection_mutex);
mutex_init(&dev->mode_config.idr_mutex);
mutex_init(&dev->mode_config.fb_lock);
INIT_LIST_HEAD(&dev->mode_config.fb_list);
Expand Down Expand Up @@ -4747,5 +4787,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
}

idr_destroy(&dev->mode_config.crtc_idr);
drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
}
EXPORT_SYMBOL(drm_mode_config_cleanup);
3 changes: 1 addition & 2 deletions drivers/gpu/drm/drm_crtc_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
struct drm_device *dev = encoder->dev;

WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex));

WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
if (connector->encoder == encoder)
return true;
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/drm_fb_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ static bool drm_fb_helper_force_kernel_mode(void)
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
continue;

/* NOTE: we use lockless flag below to avoid grabbing other
* modeset locks. So just trylock the underlying mutex
* directly:
*/
if (!mutex_trylock(&dev->mode_config.mutex)) {
error = true;
continue;
Expand Down
Loading

0 comments on commit 51fd371

Please sign in to comment.