|
@@ -37,6 +37,7 @@
|
|
#include <drm/drm_crtc.h>
|
|
#include <drm/drm_crtc.h>
|
|
#include <drm/drm_edid.h>
|
|
#include <drm/drm_edid.h>
|
|
#include <drm/drm_fourcc.h>
|
|
#include <drm/drm_fourcc.h>
|
|
|
|
+#include <drm/drm_modeset_lock.h>
|
|
|
|
|
|
#include "drm_crtc_internal.h"
|
|
#include "drm_crtc_internal.h"
|
|
|
|
|
|
@@ -50,14 +51,42 @@
|
|
*/
|
|
*/
|
|
void drm_modeset_lock_all(struct drm_device *dev)
|
|
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);
|
|
EXPORT_SYMBOL(drm_modeset_lock_all);
|
|
|
|
|
|
@@ -69,12 +98,17 @@ EXPORT_SYMBOL(drm_modeset_lock_all);
|
|
*/
|
|
*/
|
|
void drm_modeset_unlock_all(struct drm_device *dev)
|
|
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);
|
|
mutex_unlock(&dev->mode_config.mutex);
|
|
}
|
|
}
|
|
@@ -95,9 +129,9 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
|
|
return;
|
|
return;
|
|
|
|
|
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
|
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));
|
|
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
|
|
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
|
|
@@ -671,6 +705,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(drm_framebuffer_remove);
|
|
EXPORT_SYMBOL(drm_framebuffer_remove);
|
|
|
|
|
|
|
|
+DEFINE_WW_CLASS(crtc_ww_class);
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* drm_crtc_init_with_planes - Initialise a new CRTC object with
|
|
* drm_crtc_init_with_planes - Initialise a new CRTC object with
|
|
* specified primary and cursor planes.
|
|
* specified primary and cursor planes.
|
|
@@ -690,6 +726,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
|
|
void *cursor,
|
|
void *cursor,
|
|
const struct drm_crtc_funcs *funcs)
|
|
const struct drm_crtc_funcs *funcs)
|
|
{
|
|
{
|
|
|
|
+ struct drm_mode_config *config = &dev->mode_config;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
crtc->dev = dev;
|
|
crtc->dev = dev;
|
|
@@ -697,8 +734,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
|
|
crtc->invert_dimensions = false;
|
|
crtc->invert_dimensions = false;
|
|
|
|
|
|
drm_modeset_lock_all(dev);
|
|
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);
|
|
ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
|
|
if (ret)
|
|
if (ret)
|
|
@@ -706,8 +744,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
|
|
|
|
|
|
crtc->base.properties = &crtc->properties;
|
|
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;
|
|
crtc->primary = primary;
|
|
if (primary)
|
|
if (primary)
|
|
@@ -735,6 +773,8 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
|
|
kfree(crtc->gamma_store);
|
|
kfree(crtc->gamma_store);
|
|
crtc->gamma_store = NULL;
|
|
crtc->gamma_store = NULL;
|
|
|
|
|
|
|
|
+ drm_modeset_lock_fini(&crtc->mutex);
|
|
|
|
+
|
|
drm_mode_object_put(dev, &crtc->base);
|
|
drm_mode_object_put(dev, &crtc->base);
|
|
list_del(&crtc->head);
|
|
list_del(&crtc->head);
|
|
dev->mode_config.num_crtc--;
|
|
dev->mode_config.num_crtc--;
|
|
@@ -1798,7 +1838,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|
DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
|
|
DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
|
|
|
|
|
|
mutex_lock(&dev->mode_config.mutex);
|
|
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);
|
|
connector = drm_connector_find(dev, out_resp->connector_id);
|
|
if (!connector) {
|
|
if (!connector) {
|
|
@@ -1897,7 +1937,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
|
|
out_resp->count_encoders = encoders_count;
|
|
out_resp->count_encoders = encoders_count;
|
|
|
|
|
|
out:
|
|
out:
|
|
- mutex_unlock(&dev->mode_config.connection_mutex);
|
|
|
|
|
|
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
|
mutex_unlock(&dev->mode_config.mutex);
|
|
mutex_unlock(&dev->mode_config.mutex);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
@@ -2481,7 +2521,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
}
|
|
}
|
|
|
|
|
|
- mutex_lock(&crtc->mutex);
|
|
|
|
|
|
+ drm_modeset_lock(&crtc->mutex, NULL);
|
|
if (req->flags & DRM_MODE_CURSOR_BO) {
|
|
if (req->flags & DRM_MODE_CURSOR_BO) {
|
|
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
|
|
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
|
|
ret = -ENXIO;
|
|
ret = -ENXIO;
|
|
@@ -2505,7 +2545,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
out:
|
|
out:
|
|
- mutex_unlock(&crtc->mutex);
|
|
|
|
|
|
+ drm_modeset_unlock(&crtc->mutex);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
@@ -4198,7 +4238,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|
if (!crtc)
|
|
if (!crtc)
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
|
|
|
|
- mutex_lock(&crtc->mutex);
|
|
|
|
|
|
+ drm_modeset_lock(&crtc->mutex, NULL);
|
|
if (crtc->primary->fb == NULL) {
|
|
if (crtc->primary->fb == NULL) {
|
|
/* The framebuffer is currently unbound, presumably
|
|
/* The framebuffer is currently unbound, presumably
|
|
* due to a hotplug event, that userspace has not
|
|
* due to a hotplug event, that userspace has not
|
|
@@ -4282,7 +4322,7 @@ out:
|
|
drm_framebuffer_unreference(fb);
|
|
drm_framebuffer_unreference(fb);
|
|
if (old_fb)
|
|
if (old_fb)
|
|
drm_framebuffer_unreference(old_fb);
|
|
drm_framebuffer_unreference(old_fb);
|
|
- mutex_unlock(&crtc->mutex);
|
|
|
|
|
|
+ drm_modeset_unlock(&crtc->mutex);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -4647,7 +4687,7 @@ EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
|
|
void drm_mode_config_init(struct drm_device *dev)
|
|
void drm_mode_config_init(struct drm_device *dev)
|
|
{
|
|
{
|
|
mutex_init(&dev->mode_config.mutex);
|
|
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.idr_mutex);
|
|
mutex_init(&dev->mode_config.fb_lock);
|
|
mutex_init(&dev->mode_config.fb_lock);
|
|
INIT_LIST_HEAD(&dev->mode_config.fb_list);
|
|
INIT_LIST_HEAD(&dev->mode_config.fb_list);
|
|
@@ -4747,5 +4787,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
|
}
|
|
}
|
|
|
|
|
|
idr_destroy(&dev->mode_config.crtc_idr);
|
|
idr_destroy(&dev->mode_config.crtc_idr);
|
|
|
|
+ drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(drm_mode_config_cleanup);
|
|
EXPORT_SYMBOL(drm_mode_config_cleanup);
|