Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5270 → Rev 5271

/drivers/video/drm/drm_crtc.c
40,102 → 40,12
#include <drm/drm_modeset_lock.h>
 
#include "drm_crtc_internal.h"
#include "drm_internal.h"
 
static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
struct drm_mode_fb_cmd2 *r,
struct drm_file *file_priv);
 
/**
* drm_modeset_lock_all - take all modeset locks
* @dev: drm device
*
* This function takes all modeset locks, suitable where a more fine-grained
* scheme isn't (yet) implemented. Locks must be dropped with
* drm_modeset_unlock_all.
*/
void drm_modeset_lock_all(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx;
int ret;
 
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (WARN_ON(!ctx))
return;
 
mutex_lock(&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);
 
/**
* drm_modeset_unlock_all - drop all modeset locks
* @dev: device
*
* This function drop all modeset locks taken by drm_modeset_lock_all.
*/
void drm_modeset_unlock_all(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
 
if (WARN_ON(!ctx))
return;
 
config->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
 
kfree(ctx);
 
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_modeset_unlock_all);
 
/**
* drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
* @dev: device
*
* Useful as a debug assert.
*/
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
{
struct drm_crtc *crtc;
 
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!drm_modeset_is_locked(&crtc->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);
 
/* Avoid boilerplate. I'm tired of typing. */
#define DRM_ENUM_NAME_FN(fnname, list) \
const char *fnname(int val) \
511,9 → 421,6
if (ret)
goto out;
 
/* Grab the idr reference. */
drm_framebuffer_reference(fb);
 
dev->mode_config.num_fb++;
list_add(&fb->head, &dev->mode_config.fb_list);
out:
523,10 → 430,34
}
EXPORT_SYMBOL(drm_framebuffer_init);
 
/* dev->mode_config.fb_lock must be held! */
static void __drm_framebuffer_unregister(struct drm_device *dev,
struct drm_framebuffer *fb)
{
mutex_lock(&dev->mode_config.idr_mutex);
idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
mutex_unlock(&dev->mode_config.idr_mutex);
 
fb->base.id = 0;
}
 
static void drm_framebuffer_free(struct kref *kref)
{
struct drm_framebuffer *fb =
container_of(kref, struct drm_framebuffer, refcount);
struct drm_device *dev = fb->dev;
 
/*
* The lookup idr holds a weak reference, which has not necessarily been
* removed at this point. Check for that.
*/
mutex_lock(&dev->mode_config.fb_lock);
if (fb->base.id) {
/* Mark fb as reaped and drop idr ref. */
__drm_framebuffer_unregister(dev, fb);
}
mutex_unlock(&dev->mode_config.fb_lock);
 
fb->funcs->destroy(fb);
}
 
608,19 → 539,6
kref_put(&fb->refcount, drm_framebuffer_free_bug);
}
 
/* dev->mode_config.fb_lock must be held! */
static void __drm_framebuffer_unregister(struct drm_device *dev,
struct drm_framebuffer *fb)
{
mutex_lock(&dev->mode_config.idr_mutex);
idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
mutex_unlock(&dev->mode_config.idr_mutex);
 
fb->base.id = 0;
 
__drm_framebuffer_unreference(fb);
}
 
/**
* drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
* @fb: fb to unregister
760,14 → 678,10
crtc->funcs = funcs;
crtc->invert_dimensions = false;
 
drm_modeset_lock_all(dev);
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;
return ret;
 
crtc->base.properties = &crtc->properties;
 
781,10 → 695,7
if (cursor)
cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
 
out:
drm_modeset_unlock_all(dev);
 
return ret;
return 0;
}
EXPORT_SYMBOL(drm_crtc_init_with_planes);
 
808,6 → 719,12
drm_mode_object_put(dev, &crtc->base);
list_del(&crtc->head);
dev->mode_config.num_crtc--;
 
WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
if (crtc->state && crtc->funcs->atomic_destroy_state)
crtc->funcs->atomic_destroy_state(crtc, crtc->state);
 
memset(crtc, 0, sizeof(*crtc));
}
EXPORT_SYMBOL(drm_crtc_cleanup);
 
949,10 → 866,43
connector->name = NULL;
list_del(&connector->head);
dev->mode_config.num_connector--;
 
WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
if (connector->state && connector->funcs->atomic_destroy_state)
connector->funcs->atomic_destroy_state(connector,
connector->state);
 
memset(connector, 0, sizeof(*connector));
}
EXPORT_SYMBOL(drm_connector_cleanup);
 
/**
* drm_connector_index - find the index of a registered connector
* @connector: connector to find index for
*
* Given a registered connector, return the index of that connector within a DRM
* device's list of connectors.
*/
unsigned int drm_connector_index(struct drm_connector *connector)
{
unsigned int index = 0;
struct drm_connector *tmp;
struct drm_mode_config *config = &connector->dev->mode_config;
 
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
if (tmp == connector)
return index;
 
index++;
}
 
BUG();
}
EXPORT_SYMBOL(drm_connector_index);
 
/**
* drm_connector_register - register a connector
* @connector: the connector to register
*
1052,6 → 1002,8
list_del(&bridge->head);
dev->mode_config.num_bridge--;
drm_modeset_unlock_all(dev);
 
memset(bridge, 0, sizeof(*bridge));
}
EXPORT_SYMBOL(drm_bridge_cleanup);
 
1118,10 → 1070,11
drm_modeset_lock_all(dev);
drm_mode_object_put(dev, &encoder->base);
kfree(encoder->name);
encoder->name = NULL;
list_del(&encoder->head);
dev->mode_config.num_encoder--;
drm_modeset_unlock_all(dev);
 
memset(encoder, 0, sizeof(*encoder));
}
EXPORT_SYMBOL(drm_encoder_cleanup);
 
1148,12 → 1101,12
{
int ret;
 
drm_modeset_lock_all(dev);
 
ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
if (ret)
goto out;
return ret;
 
drm_modeset_lock_init(&plane->mutex);
 
plane->base.properties = &plane->properties;
plane->dev = dev;
plane->funcs = funcs;
1162,8 → 1115,7
if (!plane->format_types) {
DRM_DEBUG_KMS("out of memory when allocating plane\n");
drm_mode_object_put(dev, &plane->base);
ret = -ENOMEM;
goto out;
return -ENOMEM;
}
 
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
1180,10 → 1132,7
dev->mode_config.plane_type_property,
plane->type);
 
out:
drm_modeset_unlock_all(dev);
 
return ret;
return 0;
}
EXPORT_SYMBOL(drm_universal_plane_init);
 
1241,10 → 1190,39
if (plane->type == DRM_PLANE_TYPE_OVERLAY)
dev->mode_config.num_overlay_plane--;
drm_modeset_unlock_all(dev);
 
WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
if (plane->state && plane->funcs->atomic_destroy_state)
plane->funcs->atomic_destroy_state(plane, plane->state);
 
memset(plane, 0, sizeof(*plane));
}
EXPORT_SYMBOL(drm_plane_cleanup);
 
/**
* drm_plane_index - find the index of a registered plane
* @plane: plane to find index for
*
* Given a registered plane, return the index of that CRTC within a DRM
* device's list of planes.
*/
unsigned int drm_plane_index(struct drm_plane *plane)
{
unsigned int index = 0;
struct drm_plane *tmp;
 
list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) {
if (tmp == plane)
return index;
 
index++;
}
 
BUG();
}
EXPORT_SYMBOL(drm_plane_index);
 
/**
* drm_plane_force_disable - Forcibly disable a plane
* @plane: plane to disable
*
1255,19 → 1233,21
*/
void drm_plane_force_disable(struct drm_plane *plane)
{
struct drm_framebuffer *old_fb = plane->fb;
int ret;
 
if (!old_fb)
if (!plane->fb)
return;
 
plane->old_fb = plane->fb;
ret = plane->funcs->disable_plane(plane);
if (ret) {
DRM_ERROR("failed to disable plane with busy fb\n");
plane->old_fb = NULL;
return;
}
/* disconnect the plane from the fb and crtc: */
__drm_framebuffer_unreference(old_fb);
__drm_framebuffer_unreference(plane->old_fb);
plane->old_fb = NULL;
plane->fb = NULL;
plane->crtc = NULL;
}
1298,6 → 1278,11
"PATH", 0);
dev->mode_config.path_property = dev_path;
 
dev->mode_config.tile_property = drm_property_create(dev,
DRM_MODE_PROP_BLOB |
DRM_MODE_PROP_IMMUTABLE,
"TILE", 0);
 
return 0;
}
 
1358,12 → 1343,13
* responsible for allocating a list of format names and passing them to
* this routine.
*/
int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
int drm_mode_create_tv_properties(struct drm_device *dev,
unsigned int num_modes,
char *modes[])
{
struct drm_property *tv_selector;
struct drm_property *tv_subconnector;
int i;
unsigned int i;
 
if (dev->mode_config.tv_select_subconnector_property)
return 0;
1461,7 → 1447,7
* connectors.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
{
1505,6 → 1491,30
}
EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
 
/**
* drm_mode_create_suggested_offset_properties - create suggests offset properties
* @dev: DRM device
*
* Create the the suggested x/y offset property for connectors.
*/
int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
{
if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
return 0;
 
dev->mode_config.suggested_x_property =
drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
 
dev->mode_config.suggested_y_property =
drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
 
if (dev->mode_config.suggested_x_property == NULL ||
dev->mode_config.suggested_y_property == NULL)
return -ENOMEM;
return 0;
}
EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
 
static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
{
uint32_t total_objects = 0;
1621,7 → 1631,7
* the caller.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
static int drm_crtc_convert_umode(struct drm_display_mode *out,
const struct drm_mode_modeinfo *in)
1666,7 → 1676,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getresources(struct drm_device *dev, void *data,
struct drm_file *file_priv)
1717,7 → 1727,9
card_res->count_fbs = fb_count;
mutex_unlock(&file_priv->fbs_lock);
 
drm_modeset_lock_all(dev);
/* mode_config.mutex protects the connector list against e.g. DP MST
* connector hot-adding. CRTC/Plane lists are invariant. */
mutex_lock(&dev->mode_config.mutex);
if (!drm_is_primary_client(file_priv)) {
 
mode_group = NULL;
1837,7 → 1849,7
card_res->count_connectors, card_res->count_encoders);
 
out:
drm_modeset_unlock_all(dev);
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
 
1852,7 → 1864,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getcrtc(struct drm_device *dev,
void *data, struct drm_file *file_priv)
1859,19 → 1871,15
{
struct drm_mode_crtc *crtc_resp = data;
struct drm_crtc *crtc;
int ret = 0;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
drm_modeset_lock_all(dev);
 
crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
if (!crtc) {
ret = -ENOENT;
goto out;
}
if (!crtc)
return -ENOENT;
 
drm_modeset_lock_crtc(crtc, crtc->primary);
crtc_resp->x = crtc->x;
crtc_resp->y = crtc->y;
crtc_resp->gamma_size = crtc->gamma_size;
1888,10 → 1896,9
} else {
crtc_resp->mode_valid = 0;
}
drm_modeset_unlock_crtc(crtc);
 
out:
drm_modeset_unlock_all(dev);
return ret;
return 0;
}
 
static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
1907,6 → 1914,15
return true;
}
 
static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
{
/* For atomic drivers only state objects are synchronously updated and
* protected by modeset locks, so check those first. */
if (connector->state)
return connector->state->best_encoder;
return connector->encoder;
}
 
/**
* drm_mode_getconnector - get connector configuration
* @dev: drm device for the ioctl
1918,7 → 1934,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getconnector(struct drm_device *dev, void *data,
struct drm_file *file_priv)
1925,6 → 1941,7
{
struct drm_mode_get_connector *out_resp = data;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_display_mode *mode;
int mode_count = 0;
int props_count = 0;
1980,8 → 1997,10
out_resp->subpixel = connector->display_info.subpixel_order;
out_resp->connection = connector->status;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
if (connector->encoder)
out_resp->encoder_id = connector->encoder->base.id;
 
encoder = drm_connector_get_encoder(connector);
if (encoder)
out_resp->encoder_id = encoder->base.id;
else
out_resp->encoder_id = 0;
drm_modeset_unlock(&dev->mode_config.connection_mutex);
2051,6 → 2070,33
return ret;
}
 
static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
{
struct drm_connector *connector;
struct drm_device *dev = encoder->dev;
bool uses_atomic = false;
 
/* For atomic drivers only state objects are synchronously updated and
* protected by modeset locks, so check those first. */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (!connector->state)
continue;
 
uses_atomic = true;
 
if (connector->state->best_encoder != encoder)
continue;
 
return connector->state->crtc;
}
 
/* Don't return stale data (e.g. pending async disable). */
if (uses_atomic)
return NULL;
 
return encoder->crtc;
}
 
/**
* drm_mode_getencoder - get encoder configuration
* @dev: drm device for the ioctl
2062,7 → 2108,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getencoder(struct drm_device *dev, void *data,
struct drm_file *file_priv)
2069,30 → 2115,31
{
struct drm_mode_get_encoder *enc_resp = data;
struct drm_encoder *encoder;
int ret = 0;
struct drm_crtc *crtc;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
drm_modeset_lock_all(dev);
encoder = drm_encoder_find(dev, enc_resp->encoder_id);
if (!encoder) {
ret = -ENOENT;
goto out;
}
if (!encoder)
return -ENOENT;
 
if (encoder->crtc)
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
crtc = drm_encoder_get_crtc(encoder);
if (crtc)
enc_resp->crtc_id = crtc->base.id;
else if (encoder->crtc)
enc_resp->crtc_id = encoder->crtc->base.id;
else
enc_resp->crtc_id = 0;
drm_modeset_unlock(&dev->mode_config.connection_mutex);
 
enc_resp->encoder_type = encoder->encoder_type;
enc_resp->encoder_id = encoder->base.id;
enc_resp->possible_crtcs = encoder->possible_crtcs;
enc_resp->possible_clones = encoder->possible_clones;
 
out:
drm_modeset_unlock_all(dev);
return ret;
return 0;
}
 
/**
2106,7 → 2153,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_file *file_priv)
2115,13 → 2162,12
struct drm_mode_config *config;
struct drm_plane *plane;
uint32_t __user *plane_ptr;
int copied = 0, ret = 0;
int copied = 0;
unsigned num_planes;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
drm_modeset_lock_all(dev);
config = &dev->mode_config;
 
if (file_priv->universal_planes)
2137,6 → 2183,7
(plane_resp->count_planes >= num_planes)) {
plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 
/* Plane lists are invariant, no locking needed. */
list_for_each_entry(plane, &config->plane_list, head) {
/*
* Unless userspace set the 'universal planes'
2146,18 → 2193,14
!file_priv->universal_planes)
continue;
 
if (put_user(plane->base.id, plane_ptr + copied)) {
ret = -EFAULT;
goto out;
}
if (put_user(plane->base.id, plane_ptr + copied))
return -EFAULT;
copied++;
}
}
plane_resp->count_planes = num_planes;
 
out:
drm_modeset_unlock_all(dev);
return ret;
return 0;
}
 
/**
2171,7 → 2214,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
2179,18 → 2222,15
struct drm_mode_get_plane *plane_resp = data;
struct drm_plane *plane;
uint32_t __user *format_ptr;
int ret = 0;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
 
drm_modeset_lock_all(dev);
plane = drm_plane_find(dev, plane_resp->plane_id);
if (!plane) {
ret = -ENOENT;
goto out;
}
if (!plane)
return -ENOENT;
 
drm_modeset_lock(&plane->mutex, NULL);
if (plane->crtc)
plane_resp->crtc_id = plane->crtc->base.id;
else
2200,6 → 2240,7
plane_resp->fb_id = plane->fb->base.id;
else
plane_resp->fb_id = 0;
drm_modeset_unlock(&plane->mutex);
 
plane_resp->plane_id = plane->base.id;
plane_resp->possible_crtcs = plane->possible_crtcs;
2215,15 → 2256,12
if (copy_to_user(format_ptr,
plane->format_types,
sizeof(uint32_t) * plane->format_count)) {
ret = -EFAULT;
goto out;
return -EFAULT;
}
}
plane_resp->count_format_types = plane->format_count;
 
out:
drm_modeset_unlock_all(dev);
return ret;
return 0;
}
 
/*
2235,7 → 2273,7
*
* src_{x,y,w,h} are provided in 16.16 fixed point format
*/
static int setplane_internal(struct drm_plane *plane,
static int __setplane_internal(struct drm_plane *plane,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int32_t crtc_x, int32_t crtc_y,
2244,24 → 2282,20
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
struct drm_device *dev = plane->dev;
struct drm_framebuffer *old_fb = NULL;
int ret = 0;
unsigned int fb_width, fb_height;
int i;
unsigned int i;
 
/* No fb means shut it down */
if (!fb) {
drm_modeset_lock_all(dev);
old_fb = plane->fb;
plane->old_fb = plane->fb;
ret = plane->funcs->disable_plane(plane);
if (!ret) {
plane->crtc = NULL;
plane->fb = NULL;
} else {
old_fb = NULL;
plane->old_fb = NULL;
}
drm_modeset_unlock_all(dev);
goto out;
}
 
2301,8 → 2335,7
goto out;
}
 
drm_modeset_lock_all(dev);
old_fb = plane->fb;
plane->old_fb = plane->fb;
ret = plane->funcs->update_plane(plane, crtc, fb,
crtc_x, crtc_y, crtc_w, crtc_h,
src_x, src_y, src_w, src_h);
2311,18 → 2344,37
plane->fb = fb;
fb = NULL;
} else {
old_fb = NULL;
plane->old_fb = NULL;
}
drm_modeset_unlock_all(dev);
 
out:
if (fb)
drm_framebuffer_unreference(fb);
if (old_fb)
drm_framebuffer_unreference(old_fb);
if (plane->old_fb)
drm_framebuffer_unreference(plane->old_fb);
plane->old_fb = NULL;
 
return ret;
}
 
static int setplane_internal(struct drm_plane *plane,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int32_t crtc_x, int32_t crtc_y,
uint32_t crtc_w, uint32_t crtc_h,
/* src_{x,y,w,h} values are 16.16 fixed point */
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
int ret;
 
drm_modeset_lock_all(plane->dev);
ret = __setplane_internal(plane, crtc, fb,
crtc_x, crtc_y, crtc_w, crtc_h,
src_x, src_y, src_w, src_h);
drm_modeset_unlock_all(plane->dev);
 
return ret;
}
 
/**
2336,13 → 2388,12
* valid crtc).
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_setplane(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_mode_set_plane *plane_req = data;
struct drm_mode_object *obj;
struct drm_plane *plane;
struct drm_crtc *crtc = NULL;
struct drm_framebuffer *fb = NULL;
2365,14 → 2416,12
* First, find the plane, crtc, and fb objects. If not available,
* we don't bother to call the driver.
*/
obj = drm_mode_object_find(dev, plane_req->plane_id,
DRM_MODE_OBJECT_PLANE);
if (!obj) {
plane = drm_plane_find(dev, plane_req->plane_id);
if (!plane) {
DRM_DEBUG_KMS("Unknown plane ID %d\n",
plane_req->plane_id);
return -ENOENT;
}
plane = obj_to_plane(obj);
 
if (plane_req->fb_id) {
fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
2382,14 → 2431,12
return -ENOENT;
}
 
obj = drm_mode_object_find(dev, plane_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!obj) {
crtc = drm_crtc_find(dev, plane_req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
plane_req->crtc_id);
return -ENOENT;
}
crtc = obj_to_crtc(obj);
}
 
/*
2412,7 → 2459,7
* interface. The only thing it adds is correct refcounting dance.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_set_config_internal(struct drm_mode_set *set)
{
2427,7 → 2474,7
* crtcs. Atomic modeset will have saner semantics ...
*/
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
tmp->old_fb = tmp->primary->fb;
tmp->primary->old_fb = tmp->primary->fb;
 
fb = set->fb;
 
2505,7 → 2552,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_setcrtc(struct drm_device *dev, void *data,
struct drm_file *file_priv)
2674,10 → 2721,12
* If this crtc has a universal cursor plane, call that plane's update
* handler rather than using legacy cursor handlers.
*/
if (crtc->cursor)
return drm_mode_cursor_universal(crtc, req, file_priv);
drm_modeset_lock_crtc(crtc, crtc->cursor);
if (crtc->cursor) {
ret = drm_mode_cursor_universal(crtc, req, file_priv);
goto out;
}
 
drm_modeset_lock(&crtc->mutex, NULL);
if (req->flags & DRM_MODE_CURSOR_BO) {
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
ret = -ENXIO;
2701,7 → 2750,7
}
}
out:
drm_modeset_unlock(&crtc->mutex);
drm_modeset_unlock_crtc(crtc);
 
return ret;
 
2719,7 → 2768,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_cursor_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
2746,7 → 2795,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_cursor2_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
2806,12 → 2855,12
* @file_priv: drm file for the ioctl call
*
* Add a new FB to the specified CRTC, given a user request. This is the
* original addfb ioclt which only supported RGB formats.
* original addfb ioctl which only supported RGB formats.
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_addfb(struct drm_device *dev,
void *data, struct drm_file *file_priv)
2818,11 → 2867,9
{
struct drm_mode_fb_cmd *or = data;
struct drm_mode_fb_cmd2 r = {};
struct drm_mode_config *config = &dev->mode_config;
struct drm_framebuffer *fb;
int ret = 0;
int ret;
 
/* Use new struct with format internally */
/* convert to new format and call new ioctl */
r.fb_id = or->fb_id;
r.width = or->width;
r.height = or->height;
2830,30 → 2877,15
r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
r.handles[0] = or->handle;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
ret = drm_mode_addfb2(dev, &r, file_priv);
if (ret)
return ret;
 
if ((config->min_width > r.width) || (r.width > config->max_width))
return -EINVAL;
or->fb_id = r.fb_id;
 
if ((config->min_height > r.height) || (r.height > config->max_height))
return -EINVAL;
 
fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
if (IS_ERR(fb)) {
DRM_DEBUG_KMS("could not create framebuffer\n");
return PTR_ERR(fb);
return 0;
}
 
mutex_lock(&file_priv->fbs_lock);
or->fb_id = fb->base.id;
list_add(&fb->filp_head, &file_priv->fbs);
DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
mutex_unlock(&file_priv->fbs_lock);
 
return ret;
}
 
static int format_check(const struct drm_mode_fb_cmd2 *r)
{
uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
2943,7 → 2975,7
num_planes = drm_format_num_planes(r->pixel_format);
 
if (r->width == 0 || r->width % hsub) {
DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
return -EINVAL;
}
 
3033,7 → 3065,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_addfb2(struct drm_device *dev,
void *data, struct drm_file *file_priv)
3061,7 → 3093,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_rmfb(struct drm_device *dev,
void *data, struct drm_file *file_priv)
3115,7 → 3147,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getfb(struct drm_device *dev,
void *data, struct drm_file *file_priv)
3137,7 → 3169,8
r->bpp = fb->bits_per_pixel;
r->pitch = fb->pitches[0];
if (fb->funcs->create_handle) {
if (file_priv->is_master || capable(CAP_SYS_ADMIN)) {
if (file_priv->is_master || capable(CAP_SYS_ADMIN) ||
drm_is_control_client(file_priv)) {
ret = fb->funcs->create_handle(fb, file_priv,
&r->handle);
} else {
3175,7 → 3208,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
3255,7 → 3288,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
void drm_fb_release(struct drm_file *priv)
{
3262,7 → 3295,16
struct drm_device *dev = priv->minor->dev;
struct drm_framebuffer *fb, *tfb;
 
mutex_lock(&priv->fbs_lock);
/*
* When the file gets released that means no one else can access the fb
* list any more, so no need to grab fpriv->fbs_lock. And we need to
* avoid upsetting lockdep since the universal cursor code adds a
* framebuffer while holding mutex locks.
*
* Note that a real deadlock between fpriv->fbs_lock and the modeset
* locks is impossible here since no one else but this function can get
* at it any more.
*/
list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
 
mutex_lock(&dev->mode_config.fb_lock);
3275,7 → 3317,6
/* This will also drop the fpriv->fbs reference. */
drm_framebuffer_remove(fb);
}
mutex_unlock(&priv->fbs_lock);
}
#endif
 
3291,6 → 3332,10
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Note that the DRM core keeps a per-device list of properties and that, if
* drm_mode_config_cleanup() is called, it will destroy all properties created
* by the driver.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
3318,7 → 3363,7
 
property->flags = flags;
property->num_values = num_values;
INIT_LIST_HEAD(&property->enum_blob_list);
INIT_LIST_HEAD(&property->enum_list);
 
if (name) {
strncpy(property->name, name, DRM_PROP_NAME_LEN);
3389,9 → 3434,10
* @flags: flags specifying the property type
* @name: name of the property
* @props: enumeration lists with property bitflags
* @num_values: number of pre-defined values
* @num_props: size of the @props array
* @supported_bits: bitmask of all supported enumeration values
*
* This creates a new generic drm property which can then be attached to a drm
* This creates a new bitmask drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
3466,7 → 3512,7
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
* Userspace is allowed to set any interger value in the (min, max) range
* Userspace is allowed to set any integer value in the (min, max) range
* inclusive.
*
* Returns:
3539,8 → 3585,8
(value > 63))
return -EINVAL;
 
if (!list_empty(&property->enum_blob_list)) {
list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
if (!list_empty(&property->enum_list)) {
list_for_each_entry(prop_enum, &property->enum_list, head) {
if (prop_enum->value == value) {
strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
3558,7 → 3604,7
prop_enum->value = value;
 
property->values[index] = value;
list_add_tail(&prop_enum->head, &property->enum_blob_list);
list_add_tail(&prop_enum->head, &property->enum_list);
return 0;
}
EXPORT_SYMBOL(drm_property_add_enum);
3575,7 → 3621,7
{
struct drm_property_enum *prop_enum, *pt;
 
list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
list_del(&prop_enum->head);
kfree(prop_enum);
}
3679,17 → 3725,20
 
#if 0
/**
* drm_mode_getproperty_ioctl - get the current value of a connector's property
* drm_mode_getproperty_ioctl - get the property metadata
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
*
* This function retrieves the current value for an connectors's property.
* This function retrieves the metadata for a given property, like the different
* possible values for an enum property or the limits for a range property.
*
* Blob properties are special
*
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getproperty_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
3697,16 → 3746,12
struct drm_mode_get_property *out_resp = data;
struct drm_property *property;
int enum_count = 0;
int blob_count = 0;
int value_count = 0;
int ret = 0, i;
int copied;
struct drm_property_enum *prop_enum;
struct drm_mode_property_enum __user *enum_ptr;
struct drm_property_blob *prop_blob;
uint32_t __user *blob_id_ptr;
uint64_t __user *values_ptr;
uint32_t __user *blob_length_ptr;
 
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
3720,11 → 3765,8
 
if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
list_for_each_entry(prop_enum, &property->enum_blob_list, head)
list_for_each_entry(prop_enum, &property->enum_list, head)
enum_count++;
} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
list_for_each_entry(prop_blob, &property->enum_blob_list, head)
blob_count++;
}
 
value_count = property->num_values;
3749,7 → 3791,7
if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
copied = 0;
enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
list_for_each_entry(prop_enum, &property->enum_list, head) {
 
if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
ret = -EFAULT;
3767,28 → 3809,16
out_resp->count_enum_blobs = enum_count;
}
 
if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
copied = 0;
blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
 
list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
ret = -EFAULT;
goto done;
}
 
if (put_user(prop_blob->length, blob_length_ptr + copied)) {
ret = -EFAULT;
goto done;
}
 
copied++;
}
}
out_resp->count_enum_blobs = blob_count;
}
/*
* NOTE: The idea seems to have been to use this to read all the blob
* property values. But nothing ever added them to the corresponding
* list, userspace always used the special-purpose get_blob ioctl to
* read the value for a blob property. It also doesn't make a lot of
* sense to return values here when everything else is just metadata for
* the property itself.
*/
if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
out_resp->count_enum_blobs = 0;
done:
drm_modeset_unlock_all(dev);
return ret;
3795,8 → 3825,9
}
#endif
 
static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
void *data)
static struct drm_property_blob *
drm_property_create_blob(struct drm_device *dev, size_t length,
const void *data)
{
struct drm_property_blob *blob;
int ret;
3843,7 → 3874,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_getblob_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
3878,12 → 3909,25
}
#endif
 
/**
* drm_mode_connector_set_path_property - set tile property on connector
* @connector: connector to set property on.
* @path: path to use for property.
*
* This creates a property to expose to userspace to specify a
* connector path. This is mainly used for DisplayPort MST where
* connectors have a topology and we want to allow userspace to give
* them more meaningful names.
*
* Returns:
* Zero on success, negative errno on failure.
*/
int drm_mode_connector_set_path_property(struct drm_connector *connector,
char *path)
const char *path)
{
struct drm_device *dev = connector->dev;
int ret, size;
size = strlen(path) + 1;
size_t size = strlen(path) + 1;
int ret;
 
connector->path_blob_ptr = drm_property_create_blob(connector->dev,
size, path);
3898,6 → 3942,52
EXPORT_SYMBOL(drm_mode_connector_set_path_property);
 
/**
* drm_mode_connector_set_tile_property - set tile property on connector
* @connector: connector to set property on.
*
* This looks up the tile information for a connector, and creates a
* property for userspace to parse if it exists. The property is of
* the form of 8 integers using ':' as a separator.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_connector_set_tile_property(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
int ret, size;
char tile[256];
 
if (connector->tile_blob_ptr)
drm_property_destroy_blob(dev, connector->tile_blob_ptr);
 
if (!connector->has_tile) {
connector->tile_blob_ptr = NULL;
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.tile_property, 0);
return ret;
}
 
snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
connector->tile_group->id, connector->tile_is_single_monitor,
connector->num_h_tile, connector->num_v_tile,
connector->tile_h_loc, connector->tile_v_loc,
connector->tile_h_size, connector->tile_v_size);
size = strlen(tile) + 1;
 
connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
size, tile);
if (!connector->tile_blob_ptr)
return -EINVAL;
 
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.tile_property,
connector->tile_blob_ptr->base.id);
return ret;
}
EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
 
/**
* drm_mode_connector_update_edid_property - update the edid property of a connector
* @connector: drm connector
* @edid: new value of the edid property
3909,10 → 3999,11
* Zero on success, errno on failure.
*/
int drm_mode_connector_update_edid_property(struct drm_connector *connector,
struct edid *edid)
const struct edid *edid)
{
struct drm_device *dev = connector->dev;
int ret, size;
size_t size;
int ret;
 
/* ignore requests to set edid when overridden */
if (connector->override_edid)
3942,8 → 4033,8
}
EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
 
#if 0
 
 
static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t value)
3980,12 → 4071,25
return ret;
}
 
static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
/**
* drm_mode_plane_set_obj_prop - set the value of a property
* @plane: drm plane object to set property value for
* @property: property to set
* @value: value the property should be set to
*
* This functions sets a given property on a given plane object. This function
* calls the driver's ->set_property callback and changes the software state of
* the property if the callback succeeds.
*
* Returns:
* Zero on success, error code on failure.
*/
int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
struct drm_property *property,
uint64_t value)
{
int ret = -EINVAL;
struct drm_plane *plane = obj_to_plane(obj);
struct drm_mode_object *obj = &plane->base;
 
if (plane->funcs->set_property)
ret = plane->funcs->set_property(plane, property, value);
3994,9 → 4098,11
 
return ret;
}
EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
#if 0
/**
* drm_mode_getproperty_ioctl - get the current value of a object's property
* drm_mode_obj_get_properties_ioctl - get the current value of a object's property
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
4008,7 → 4114,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
4080,7 → 4186,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
4132,7 → 4238,8
ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
break;
case DRM_MODE_OBJECT_PLANE:
ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
property, arg->value);
break;
}
 
4152,7 → 4259,7
* possible_clones and possible_crtcs bitmasks.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_connector_attach_encoder(struct drm_connector *connector,
struct drm_encoder *encoder)
4179,7 → 4286,7
* fixed gamma table size.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size)
4209,7 → 4316,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_gamma_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
4281,7 → 4388,7
* Called by the user via ioctl.
*
* Returns:
* Zero on success, errno on failure.
* Zero on success, negative errno on failure.
*/
int drm_mode_gamma_get_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
4345,9 → 4452,14
void drm_mode_config_reset(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_encoder *encoder;
struct drm_connector *connector;
 
list_for_each_entry(plane, &dev->mode_config.plane_list, head)
if (plane->funcs->reset)
plane->funcs->reset(plane);
 
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
if (crtc->funcs->reset)
crtc->funcs->reset(crtc);
4576,6 → 4688,36
EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
 
/**
* drm_rotation_simplify() - Try to simplify the rotation
* @rotation: Rotation to be simplified
* @supported_rotations: Supported rotations
*
* Attempt to simplify the rotation to a form that is supported.
* Eg. if the hardware supports everything except DRM_REFLECT_X
* one could call this function like this:
*
* drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) |
* BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) |
* BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y));
*
* to eliminate the DRM_ROTATE_X flag. Depending on what kind of
* transforms the hardware supports, this function may not
* be able to produce a supported transform, so the caller should
* check the result afterwards.
*/
unsigned int drm_rotation_simplify(unsigned int rotation,
unsigned int supported_rotations)
{
if (rotation & ~supported_rotations) {
rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y);
rotation = (rotation & ~0xf) | BIT((ffs(rotation & 0xf) + 1) % 4);
}
 
return rotation;
}
EXPORT_SYMBOL(drm_rotation_simplify);
 
/**
* drm_mode_config_init - initialize DRM mode_configuration structure
* @dev: DRM device
*
4602,6 → 4744,7
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
INIT_LIST_HEAD(&dev->mode_config.plane_list);
idr_init(&dev->mode_config.crtc_idr);
idr_init(&dev->mode_config.tile_idr);
 
drm_modeset_lock_all(dev);
drm_mode_create_standard_connector_properties(dev);
4631,3 → 4774,181
*
* FIXME: cleanup any dangling user buffer objects too
*/
void drm_mode_config_cleanup(struct drm_device *dev)
{
struct drm_connector *connector, *ot;
struct drm_crtc *crtc, *ct;
struct drm_encoder *encoder, *enct;
struct drm_bridge *bridge, *brt;
struct drm_framebuffer *fb, *fbt;
struct drm_property *property, *pt;
struct drm_property_blob *blob, *bt;
struct drm_plane *plane, *plt;
 
list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
head) {
encoder->funcs->destroy(encoder);
}
 
list_for_each_entry_safe(bridge, brt,
&dev->mode_config.bridge_list, head) {
bridge->funcs->destroy(bridge);
}
 
list_for_each_entry_safe(connector, ot,
&dev->mode_config.connector_list, head) {
connector->funcs->destroy(connector);
}
 
list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
head) {
drm_property_destroy(dev, property);
}
 
list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
head) {
drm_property_destroy_blob(dev, blob);
}
 
/*
* Single-threaded teardown context, so it's not required to grab the
* fb_lock to protect against concurrent fb_list access. Contrary, it
* would actually deadlock with the drm_framebuffer_cleanup function.
*
* Also, if there are any framebuffers left, that's a driver leak now,
* so politely WARN about this.
*/
WARN_ON(!list_empty(&dev->mode_config.fb_list));
list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
drm_framebuffer_remove(fb);
}
 
list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
head) {
plane->funcs->destroy(plane);
}
 
list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
crtc->funcs->destroy(crtc);
}
 
idr_destroy(&dev->mode_config.tile_idr);
idr_destroy(&dev->mode_config.crtc_idr);
drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
}
EXPORT_SYMBOL(drm_mode_config_cleanup);
 
struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
unsigned int supported_rotations)
{
static const struct drm_prop_enum_list props[] = {
{ DRM_ROTATE_0, "rotate-0" },
{ DRM_ROTATE_90, "rotate-90" },
{ DRM_ROTATE_180, "rotate-180" },
{ DRM_ROTATE_270, "rotate-270" },
{ DRM_REFLECT_X, "reflect-x" },
{ DRM_REFLECT_Y, "reflect-y" },
};
 
return drm_property_create_bitmask(dev, 0, "rotation",
props, ARRAY_SIZE(props),
supported_rotations);
}
EXPORT_SYMBOL(drm_mode_create_rotation_property);
 
/**
* DOC: Tile group
*
* Tile groups are used to represent tiled monitors with a unique
* integer identifier. Tiled monitors using DisplayID v1.3 have
* a unique 8-byte handle, we store this in a tile group, so we
* have a common identifier for all tiles in a monitor group.
*/
static void drm_tile_group_free(struct kref *kref)
{
struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
struct drm_device *dev = tg->dev;
mutex_lock(&dev->mode_config.idr_mutex);
idr_remove(&dev->mode_config.tile_idr, tg->id);
mutex_unlock(&dev->mode_config.idr_mutex);
kfree(tg);
}
 
/**
* drm_mode_put_tile_group - drop a reference to a tile group.
* @dev: DRM device
* @tg: tile group to drop reference to.
*
* drop reference to tile group and free if 0.
*/
void drm_mode_put_tile_group(struct drm_device *dev,
struct drm_tile_group *tg)
{
kref_put(&tg->refcount, drm_tile_group_free);
}
 
/**
* drm_mode_get_tile_group - get a reference to an existing tile group
* @dev: DRM device
* @topology: 8-bytes unique per monitor.
*
* Use the unique bytes to get a reference to an existing tile group.
*
* RETURNS:
* tile group or NULL if not found.
*/
struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
char topology[8])
{
struct drm_tile_group *tg;
int id;
mutex_lock(&dev->mode_config.idr_mutex);
idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
if (!memcmp(tg->group_data, topology, 8)) {
// if (!kref_get_unless_zero(&tg->refcount))
// tg = NULL;
mutex_unlock(&dev->mode_config.idr_mutex);
return tg;
}
}
mutex_unlock(&dev->mode_config.idr_mutex);
return NULL;
}
 
/**
* drm_mode_create_tile_group - create a tile group from a displayid description
* @dev: DRM device
* @topology: 8-bytes unique per monitor.
*
* Create a tile group for the unique monitor, and get a unique
* identifier for the tile group.
*
* RETURNS:
* new tile group or error.
*/
struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
char topology[8])
{
struct drm_tile_group *tg;
int ret;
 
tg = kzalloc(sizeof(*tg), GFP_KERNEL);
if (!tg)
return ERR_PTR(-ENOMEM);
 
kref_init(&tg->refcount);
memcpy(tg->group_data, topology, 8);
tg->dev = dev;
 
mutex_lock(&dev->mode_config.idr_mutex);
ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
if (ret >= 0) {
tg->id = ret;
} else {
kfree(tg);
tg = ERR_PTR(ret);
}
 
mutex_unlock(&dev->mode_config.idr_mutex);
return tg;
}