65,8 → 65,6 |
*/ |
state->allow_modeset = true; |
|
state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); |
|
state->crtcs = kcalloc(dev->mode_config.num_crtc, |
sizeof(*state->crtcs), GFP_KERNEL); |
if (!state->crtcs) |
83,16 → 81,6 |
sizeof(*state->plane_states), GFP_KERNEL); |
if (!state->plane_states) |
goto fail; |
state->connectors = kcalloc(state->num_connector, |
sizeof(*state->connectors), |
GFP_KERNEL); |
if (!state->connectors) |
goto fail; |
state->connector_states = kcalloc(state->num_connector, |
sizeof(*state->connector_states), |
GFP_KERNEL); |
if (!state->connector_states) |
goto fail; |
|
state->dev = dev; |
|
288,8 → 276,8 |
state->crtcs[index] = crtc; |
crtc_state->state = state; |
|
DRM_DEBUG_ATOMIC("Added [CRTC:%d] %p state to %p\n", |
crtc->base.id, crtc_state, state); |
DRM_DEBUG_ATOMIC("Added [CRTC:%d:%s] %p state to %p\n", |
crtc->base.id, crtc->name, crtc_state, state); |
|
return crtc_state; |
} |
316,7 → 304,6 |
if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) |
return 0; |
|
if (state->mode_blob) |
drm_property_unreference_blob(state->mode_blob); |
state->mode_blob = NULL; |
|
363,12 → 350,9 |
if (blob == state->mode_blob) |
return 0; |
|
if (state->mode_blob) |
drm_property_unreference_blob(state->mode_blob); |
state->mode_blob = NULL; |
|
memset(&state->mode, 0, sizeof(state->mode)); |
|
if (blob) { |
if (blob->length != sizeof(struct drm_mode_modeinfo) || |
drm_mode_convert_umode(&state->mode, |
381,6 → 365,7 |
DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", |
state->mode.name, state); |
} else { |
memset(&state->mode, 0, sizeof(state->mode)); |
state->enable = false; |
DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", |
state); |
420,7 → 405,6 |
struct drm_property_blob *mode = |
drm_property_lookup_blob(dev, val); |
ret = drm_atomic_set_mode_prop_for_crtc(state, mode); |
if (mode) |
drm_property_unreference_blob(mode); |
return ret; |
} |
433,11 → 417,20 |
} |
EXPORT_SYMBOL(drm_atomic_crtc_set_property); |
|
/* |
/** |
* drm_atomic_crtc_get_property - get property value from CRTC state |
* @crtc: the drm CRTC to set a property on |
* @state: the state object to get the property value from |
* @property: the property to set |
* @val: return location for the property value |
* |
* This function handles generic/core properties and calls out to |
* driver's ->atomic_get_property() for driver properties. To ensure |
* consistent behavior you must call this function rather than the |
* driver hook directly. |
* |
* RETURNS: |
* Zero on success, error code on failure |
*/ |
static int |
drm_atomic_crtc_get_property(struct drm_crtc *crtc, |
481,8 → 474,8 |
*/ |
|
if (state->active && !state->enable) { |
DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n", |
crtc->base.id); |
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active without enabled\n", |
crtc->base.id, crtc->name); |
return -EINVAL; |
} |
|
491,14 → 484,30 |
* be able to trigger. */ |
if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && |
WARN_ON(state->enable && !state->mode_blob)) { |
DRM_DEBUG_ATOMIC("[CRTC:%d] enabled without mode blob\n", |
crtc->base.id); |
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled without mode blob\n", |
crtc->base.id, crtc->name); |
return -EINVAL; |
} |
|
if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && |
WARN_ON(!state->enable && state->mode_blob)) { |
DRM_DEBUG_ATOMIC("[CRTC:%d] disabled with mode blob\n", |
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] disabled with mode blob\n", |
crtc->base.id, crtc->name); |
return -EINVAL; |
} |
|
/* |
* Reject event generation for when a CRTC is off and stays off. |
* It wouldn't be hard to implement this, but userspace has a track |
* record of happily burning through 100% cpu (or worse, crash) when the |
* display pipe is suspended. To avoid all that fun just reject updates |
* that ask for events since likely that indicates a bug in the |
* compositor's drawing loop. This is consistent with the vblank IOCTL |
* and legacy page_flip IOCTL which also reject service on a disabled |
* pipe. |
*/ |
if (state->event && !state->active && !crtc->state->active) { |
DRM_DEBUG_ATOMIC("[CRTC:%d] requesting event but off\n", |
crtc->base.id); |
return -EINVAL; |
} |
544,8 → 553,8 |
state->planes[index] = plane; |
plane_state->state = state; |
|
DRM_DEBUG_ATOMIC("Added [PLANE:%d] %p state to %p\n", |
plane->base.id, plane_state, state); |
DRM_DEBUG_ATOMIC("Added [PLANE:%d:%s] %p state to %p\n", |
plane->base.id, plane->name, plane_state, state); |
|
if (plane_state->crtc) { |
struct drm_crtc_state *crtc_state; |
620,11 → 629,20 |
} |
EXPORT_SYMBOL(drm_atomic_plane_set_property); |
|
/* |
/** |
* drm_atomic_plane_get_property - get property value from plane state |
* @plane: the drm plane to set a property on |
* @state: the state object to get the property value from |
* @property: the property to set |
* @val: return location for the property value |
* |
* This function handles generic/core properties and calls out to |
* driver's ->atomic_get_property() for driver properties. To ensure |
* consistent behavior you must call this function rather than the |
* driver hook directly. |
* |
* RETURNS: |
* Zero on success, error code on failure |
*/ |
static int |
drm_atomic_plane_get_property(struct drm_plane *plane, |
756,8 → 774,8 |
} |
|
if (plane_switching_crtc(state->state, plane, state)) { |
DRM_DEBUG_ATOMIC("[PLANE:%d] switching CRTC directly\n", |
plane->base.id); |
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n", |
plane->base.id, plane->name); |
return -EINVAL; |
} |
|
793,19 → 811,27 |
|
index = drm_connector_index(connector); |
|
/* |
* Construction of atomic state updates can race with a connector |
* hot-add which might overflow. In this case flip the table and just |
* restart the entire ioctl - no one is fast enough to livelock a cpu |
* with physical hotplug events anyway. |
* |
* Note that we only grab the indexes once we have the right lock to |
* prevent hotplug/unplugging of connectors. So removal is no problem, |
* at most the array is a bit too large. |
*/ |
if (index >= state->num_connector) { |
DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n"); |
return ERR_PTR(-EAGAIN); |
struct drm_connector **c; |
struct drm_connector_state **cs; |
int alloc = max(index + 1, config->num_connector); |
|
c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL); |
if (!c) |
return ERR_PTR(-ENOMEM); |
|
state->connectors = c; |
memset(&state->connectors[state->num_connector], 0, |
sizeof(*state->connectors) * (alloc - state->num_connector)); |
|
cs = krealloc(state->connector_states, alloc * sizeof(*state->connector_states), GFP_KERNEL); |
if (!cs) |
return ERR_PTR(-ENOMEM); |
|
state->connector_states = cs; |
memset(&state->connector_states[state->num_connector], 0, |
sizeof(*state->connector_states) * (alloc - state->num_connector)); |
state->num_connector = alloc; |
} |
|
if (state->connector_states[index]) |
876,11 → 902,20 |
} |
EXPORT_SYMBOL(drm_atomic_connector_set_property); |
|
/* |
/** |
* drm_atomic_connector_get_property - get property value from connector state |
* @connector: the drm connector to set a property on |
* @state: the state object to get the property value from |
* @property: the property to set |
* @val: return location for the property value |
* |
* This function handles generic/core properties and calls out to |
* driver's ->atomic_get_property() for driver properties. To ensure |
* consistent behavior you must call this function rather than the |
* driver hook directly. |
* |
* RETURNS: |
* Zero on success, error code on failure |
*/ |
static int |
drm_atomic_connector_get_property(struct drm_connector *connector, |
981,8 → 1016,8 |
} |
|
if (crtc) |
DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d]\n", |
plane_state, crtc->base.id); |
DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d:%s]\n", |
plane_state, crtc->base.id, crtc->name); |
else |
DRM_DEBUG_ATOMIC("Link plane state %p to [NOCRTC]\n", |
plane_state); |
1040,17 → 1075,28 |
{ |
struct drm_crtc_state *crtc_state; |
|
if (conn_state->crtc && conn_state->crtc != crtc) { |
crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state, |
conn_state->crtc); |
|
crtc_state->connector_mask &= |
~(1 << drm_connector_index(conn_state->connector)); |
} |
|
if (crtc) { |
crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc); |
if (IS_ERR(crtc_state)) |
return PTR_ERR(crtc_state); |
|
crtc_state->connector_mask |= |
1 << drm_connector_index(conn_state->connector); |
} |
|
conn_state->crtc = crtc; |
|
if (crtc) |
DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d]\n", |
conn_state, crtc->base.id); |
DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d:%s]\n", |
conn_state, crtc->base.id, crtc->name); |
else |
DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n", |
conn_state); |
1089,8 → 1135,8 |
if (ret) |
return ret; |
|
DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d] to %p\n", |
crtc->base.id, state); |
DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d:%s] to %p\n", |
crtc->base.id, crtc->name, state); |
|
/* |
* Changed connectors are already in @state, so only need to look at the |
1149,35 → 1195,6 |
EXPORT_SYMBOL(drm_atomic_add_affected_planes); |
|
/** |
* drm_atomic_connectors_for_crtc - count number of connected outputs |
* @state: atomic state |
* @crtc: DRM crtc |
* |
* This function counts all connectors which will be connected to @crtc |
* according to @state. Useful to recompute the enable state for @crtc. |
*/ |
int |
drm_atomic_connectors_for_crtc(struct drm_atomic_state *state, |
struct drm_crtc *crtc) |
{ |
struct drm_connector *connector; |
struct drm_connector_state *conn_state; |
|
int i, num_connected_connectors = 0; |
|
for_each_connector_in_state(state, connector, conn_state, i) { |
if (conn_state->crtc == crtc) |
num_connected_connectors++; |
} |
|
DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d]\n", |
state, num_connected_connectors, crtc->base.id); |
|
return num_connected_connectors; |
} |
EXPORT_SYMBOL(drm_atomic_connectors_for_crtc); |
|
/** |
* drm_atomic_legacy_backoff - locking backoff for legacy ioctls |
* @state: atomic state |
* |
1192,14 → 1209,9 |
retry: |
drm_modeset_backoff(state->acquire_ctx); |
|
ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, |
state->acquire_ctx); |
ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx); |
if (ret) |
goto retry; |
ret = drm_modeset_lock_all_crtcs(state->dev, |
state->acquire_ctx); |
if (ret) |
goto retry; |
} |
EXPORT_SYMBOL(drm_atomic_legacy_backoff); |
|
1229,8 → 1241,8 |
for_each_plane_in_state(state, plane, plane_state, i) { |
ret = drm_atomic_plane_check(plane, plane_state); |
if (ret) { |
DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n", |
plane->base.id); |
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic core check failed\n", |
plane->base.id, plane->name); |
return ret; |
} |
} |
1238,8 → 1250,8 |
for_each_crtc_in_state(state, crtc, crtc_state, i) { |
ret = drm_atomic_crtc_check(crtc, crtc_state); |
if (ret) { |
DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n", |
crtc->base.id); |
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic core check failed\n", |
crtc->base.id, crtc->name); |
return ret; |
} |
} |
1250,8 → 1262,8 |
if (!state->allow_modeset) { |
for_each_crtc_in_state(state, crtc, crtc_state, i) { |
if (drm_atomic_crtc_needs_modeset(crtc_state)) { |
DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n", |
crtc->base.id); |
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requires full modeset\n", |
crtc->base.id, crtc->name); |
return -EINVAL; |
} |
} |
1434,7 → 1446,7 |
} |
|
/** |
* drm_atomic_update_old_fb -- Unset old_fb pointers and set plane->fb pointers. |
* drm_atomic_clean_old_fb -- Unset old_fb pointers and set plane->fb pointers. |
* |
* @dev: drm device to check. |
* @plane_mask: plane mask for planes that were updated. |