/** * drm_atomic_set_mode_for_crtc - set mode for CRTC * @state: the CRTC whose incoming state to update * @mode: kernel-internal mode to use for the CRTC, or NULL to disable * * Set a mode (originating from the kernel) on the desired CRTC state. Does * not change any other state properties, including enable, active, or * mode_changed. * * RETURNS: * Zero on success, error code on failure. Cannot return -EDEADLK. */ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, struct drm_display_mode *mode) { struct drm_mode_modeinfo umode; /* Early return for no change. */ 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; if (mode) { drm_mode_convert_to_umode(&umode, mode); state->mode_blob = drm_property_create_blob(state->crtc->dev, sizeof(umode), &umode); if (IS_ERR(state->mode_blob)) return PTR_ERR(state->mode_blob); drm_mode_copy(&state->mode, mode); state->enable = true; DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", 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); } return 0; }
/** * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC * @state: the CRTC whose incoming state to update * @blob: pointer to blob property to use for mode * * Set a mode (originating from a blob property) on the desired CRTC state. * This function will take a reference on the blob property for the CRTC state, * and release the reference held on the state's existing mode property, if any * was set. * * RETURNS: * Zero on success, error code on failure. Cannot return -EDEADLK. */ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, struct drm_property_blob *blob) { if (blob == state->mode_blob) return 0; if (state->mode_blob) drm_property_unreference_blob(state->mode_blob); state->mode_blob = NULL; if (blob) { if (blob->length != sizeof(struct drm_mode_modeinfo) || drm_mode_convert_umode(&state->mode, (const struct drm_mode_modeinfo *) blob->data)) return -EINVAL; state->mode_blob = drm_property_reference_blob(blob); state->enable = true; 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); } return 0; }
/** * drm_atomic_plane_check - check plane state * @plane: plane to check * @state: plane state to check * * Provides core sanity checks for plane state. * * RETURNS: * Zero on success, error code on failure */ static int drm_atomic_plane_check(struct drm_plane *plane, struct drm_plane_state *state) { unsigned int fb_width, fb_height; int ret; /* either *both* CRTC and FB must be set, or neither */ if (WARN_ON(state->crtc && !state->fb)) { DRM_DEBUG_ATOMIC("CRTC set but no FB\n"); return -EINVAL; } else if (WARN_ON(state->fb && !state->crtc)) { DRM_DEBUG_ATOMIC("FB set but no CRTC\n"); return -EINVAL; } /* if disabled, we don't care about the rest of the state: */ if (!state->crtc) return 0; /* Check whether this plane is usable on this CRTC */ if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { DRM_DEBUG_ATOMIC("Invalid crtc for plane\n"); return -EINVAL; } /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format); if (ret) { DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", drm_get_format_name(state->fb->pixel_format)); return ret; } /* Give drivers some help against integer overflows */ if (state->crtc_w > INT_MAX || state->crtc_x > INT_MAX - (int32_t) state->crtc_w || state->crtc_h > INT_MAX || state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { DRM_DEBUG_ATOMIC("Invalid CRTC coordinates %ux%u+%d+%d\n", state->crtc_w, state->crtc_h, state->crtc_x, state->crtc_y); return -ERANGE; } fb_width = state->fb->width << 16; fb_height = state->fb->height << 16; /* Make sure source coordinates are inside the fb. */ if (state->src_w > fb_width || state->src_x > fb_width - state->src_w || state->src_h > fb_height || state->src_y > fb_height - state->src_h) { DRM_DEBUG_ATOMIC("Invalid source coordinates " "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); return -ENOSPC; }
static int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state, const struct drm_crtc_state *new_crtc_state) { struct drm_crtc *crtc = new_crtc_state->crtc; /* NOTE: we explicitly don't enforce constraints such as primary * layer covering entire screen, since that is something we want * to allow (on hw that supports it). For hw that does not, it * should be checked in driver's crtc->atomic_check() vfunc. * * TODO: Add generic modeset state checks once we support those. */ if (new_crtc_state->active && !new_crtc_state->enable) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active without enabled\n", crtc->base.id, crtc->name); return -EINVAL; } /* The state->enable vs. state->mode_blob checks can be WARN_ON, * as this is a kernel-internal detail that userspace should never * be able to trigger. */ if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && WARN_ON(new_crtc_state->enable && !new_crtc_state->mode_blob)) { 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(!new_crtc_state->enable && new_crtc_state->mode_blob)) { 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 (new_crtc_state->event && !new_crtc_state->active && !old_crtc_state->active) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requesting event but off\n", crtc->base.id, crtc->name); return -EINVAL; } return 0; }
/** * drm_atomic_state_init - init new atomic state * @dev: DRM device * @state: atomic state * * Default implementation for filling in a new atomic state. * This should only be used by drivers which are still subclassing * &drm_atomic_state and haven't switched to &drm_private_state yet. */ int drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) { kref_init(&state->ref); /* TODO legacy paths should maybe do a better job about * setting this appropriately? */ state->allow_modeset = true; state->crtcs = kcalloc(dev->mode_config.num_crtc, sizeof(*state->crtcs), GFP_KERNEL); if (!state->crtcs) goto fail; state->planes = kcalloc(dev->mode_config.num_total_plane, sizeof(*state->planes), GFP_KERNEL); if (!state->planes) goto fail; state->dev = dev; DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state); return 0; fail: drm_atomic_state_default_release(state); return -ENOMEM; }
/** * drm_atomic_get_crtc_state - get crtc state * @state: global atomic state object * @crtc: crtc to get state object for * * This function returns the crtc state for the given crtc, allocating it if * needed. It will also grab the relevant crtc lock to make sure that the state * is consistent. * * Returns: * * Either the allocated state or the error code encoded into the pointer. When * the error is EDEADLK then the w/w mutex code has detected a deadlock and the * entire atomic sequence must be restarted. All other errors are fatal. */ struct drm_crtc_state * drm_atomic_get_crtc_state(struct drm_atomic_state *state, struct drm_crtc *crtc) { int ret, index = drm_crtc_index(crtc); struct drm_crtc_state *crtc_state; crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); if (crtc_state) return crtc_state; ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); if (ret) return ERR_PTR(ret); crtc_state = crtc->funcs->atomic_duplicate_state(crtc); if (!crtc_state) return ERR_PTR(-ENOMEM); state->crtc_states[index] = crtc_state; 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); return crtc_state; }
void msm_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; kms->funcs->prepare_commit(kms, state); drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_planes(dev, state, 0); drm_atomic_helper_commit_modeset_enables(dev, state); if (kms->funcs->commit) { DRM_DEBUG_ATOMIC("triggering commit\n"); kms->funcs->commit(kms, state); } msm_atomic_wait_for_commit_done(dev, state); kms->funcs->complete_commit(kms, state); drm_atomic_helper_commit_hw_done(state); drm_atomic_helper_cleanup_planes(dev, state); }
/** * drm_atomic_state_free - free all memory for an atomic state * @state: atomic state to deallocate * * This frees all memory associated with an atomic state, including all the * per-object state for planes, crtcs and connectors. */ void drm_atomic_state_free(struct drm_atomic_state *state) { if (!state) return; drm_atomic_state_clear(state); DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state); kfree_state(state); }
/** * drm_atomic_state_alloc - allocate atomic state * @dev: DRM device * * This allocates an empty atomic state to track updates. */ struct drm_atomic_state * drm_atomic_state_alloc(struct drm_device *dev) { struct drm_atomic_state *state; state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL; /* TODO legacy paths should maybe do a better job about * setting this appropriately? */ 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) goto fail; state->crtc_states = kcalloc(dev->mode_config.num_crtc, sizeof(*state->crtc_states), GFP_KERNEL); if (!state->crtc_states) goto fail; state->planes = kcalloc(dev->mode_config.num_total_plane, sizeof(*state->planes), GFP_KERNEL); if (!state->planes) goto fail; state->plane_states = kcalloc(dev->mode_config.num_total_plane, 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; DRM_DEBUG_ATOMIC("Allocate atomic state %p\n", state); return state; fail: kfree_state(state); return NULL; }
/** * drm_atomic_state_default_clear - clear base atomic state * @state: atomic state * * Default implementation for clearing atomic state. * This is useful for drivers that subclass the atomic state. */ void drm_atomic_state_default_clear(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_mode_config *config = &dev->mode_config; int i; DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state); for (i = 0; i < state->num_connector; i++) { struct drm_connector *connector = state->connectors[i]; if (!connector) continue; /* * FIXME: Async commits can race with connector unplugging and * there's currently nothing that prevents cleanup up state for * deleted connectors. As long as the callback doesn't look at * the connector we'll be fine though, so make sure that's the * case by setting all connector pointers to NULL. */ state->connector_states[i]->connector = NULL; connector->funcs->atomic_destroy_state(NULL, state->connector_states[i]); state->connectors[i] = NULL; state->connector_states[i] = NULL; } for (i = 0; i < config->num_crtc; i++) { struct drm_crtc *crtc = state->crtcs[i]; if (!crtc) continue; crtc->funcs->atomic_destroy_state(crtc, state->crtc_states[i]); state->crtcs[i] = NULL; state->crtc_states[i] = NULL; } for (i = 0; i < config->num_total_plane; i++) { struct drm_plane *plane = state->planes[i]; if (!plane) continue; plane->funcs->atomic_destroy_state(plane, state->plane_states[i]); state->planes[i] = NULL; state->plane_states[i] = NULL; } }
static int drm_atomic_connector_check(struct drm_connector *connector, struct drm_connector_state *state) { struct drm_crtc_state *crtc_state; struct drm_writeback_job *writeback_job = state->writeback_job; const struct drm_display_info *info = &connector->display_info; state->max_bpc = info->bpc ? info->bpc : 8; if (connector->max_bpc_property) state->max_bpc = min(state->max_bpc, state->max_requested_bpc); if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) || !writeback_job) return 0; if (writeback_job->fb && !state->crtc) { DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] framebuffer without CRTC\n", connector->base.id, connector->name); return -EINVAL; } if (state->crtc) crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); if (writeback_job->fb && !crtc_state->active) { DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] has framebuffer, but [CRTC:%d] is off\n", connector->base.id, connector->name, state->crtc->base.id); return -EINVAL; } if (writeback_job->out_fence && !writeback_job->fb) { DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] requesting out-fence without framebuffer\n", connector->base.id, connector->name); return -EINVAL; } return 0; }
/** * drm_atomic_crtc_check - check crtc state * @crtc: crtc to check * @state: crtc state to check * * Provides core sanity checks for crtc state. * * RETURNS: * Zero on success, error code on failure */ static int drm_atomic_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { /* NOTE: we explicitly don't enforce constraints such as primary * layer covering entire screen, since that is something we want * to allow (on hw that supports it). For hw that does not, it * should be checked in driver's crtc->atomic_check() vfunc. * * TODO: Add generic modeset state checks once we support those. */ if (state->active && !state->enable) { DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n", crtc->base.id); return -EINVAL; } /* The state->enable vs. state->mode_blob checks can be WARN_ON, * as this is a kernel-internal detail that userspace should never * 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); 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", crtc->base.id); return -EINVAL; } return 0; }
/** * __drm_atomic_state_free - free all memory for an atomic state * @ref: This atomic state to deallocate * * This frees all memory associated with an atomic state, including all the * per-object state for planes, crtcs and connectors. */ void __drm_atomic_state_free(struct kref *ref) { struct drm_atomic_state *state = container_of(ref, typeof(*state), ref); struct drm_mode_config *config = &state->dev->mode_config; drm_atomic_state_clear(state); DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state); if (config->funcs->atomic_state_free) { config->funcs->atomic_state_free(state); } else { drm_atomic_state_default_release(state); kfree(state); } }
/** * drm_atomic_get_plane_state - get plane state * @state: global atomic state object * @plane: plane to get state object for * * This function returns the plane state for the given plane, allocating it if * needed. It will also grab the relevant plane lock to make sure that the state * is consistent. * * Returns: * * Either the allocated state or the error code encoded into the pointer. When * the error is EDEADLK then the w/w mutex code has detected a deadlock and the * entire atomic sequence must be restarted. All other errors are fatal. */ struct drm_plane_state * drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane) { int ret, index = drm_plane_index(plane); struct drm_plane_state *plane_state; WARN_ON(!state->acquire_ctx); /* the legacy pointers should never be set */ WARN_ON(plane->fb); WARN_ON(plane->old_fb); WARN_ON(plane->crtc); plane_state = drm_atomic_get_existing_plane_state(state, plane); if (plane_state) return plane_state; ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx); if (ret) return ERR_PTR(ret); plane_state = plane->funcs->atomic_duplicate_state(plane); if (!plane_state) return ERR_PTR(-ENOMEM); state->planes[index].state = plane_state; state->planes[index].ptr = plane; state->planes[index].old_state = plane->state; state->planes[index].new_state = plane_state; plane_state->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; crtc_state = drm_atomic_get_crtc_state(state, plane_state->crtc); if (IS_ERR(crtc_state)) return ERR_CAST(crtc_state); } return plane_state; }
/** * drm_atomic_state_clear - clear state object * @state: atomic state * * When the w/w mutex algorithm detects a deadlock we need to back off and drop * all locks. So someone else could sneak in and change the current modeset * configuration. Which means that all the state assembled in @state is no * longer an atomic update to the current state, but to some arbitrary earlier * state. Which could break assumptions the driver's ->atomic_check likely * relies on. * * Hence we must clear all cached state and completely start over, using this * function. */ void drm_atomic_state_clear(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_mode_config *config = &dev->mode_config; int i; DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state); for (i = 0; i < state->num_connector; i++) { struct drm_connector *connector = state->connectors[i]; if (!connector) continue; WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); connector->funcs->atomic_destroy_state(connector, state->connector_states[i]); state->connectors[i] = NULL; state->connector_states[i] = NULL; } for (i = 0; i < config->num_crtc; i++) { struct drm_crtc *crtc = state->crtcs[i]; if (!crtc) continue; crtc->funcs->atomic_destroy_state(crtc, state->crtc_states[i]); state->crtcs[i] = NULL; state->crtc_states[i] = NULL; } for (i = 0; i < config->num_total_plane; i++) { struct drm_plane *plane = state->planes[i]; if (!plane) continue; plane->funcs->atomic_destroy_state(plane, state->plane_states[i]); state->planes[i] = NULL; state->plane_states[i] = NULL; } }
/** * drm_atomic_crtc_check - check crtc state * @crtc: crtc to check * @state: crtc state to check * * Provides core sanity checks for crtc state. * * RETURNS: * Zero on success, error code on failure */ static int drm_atomic_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { /* NOTE: we explicitly don't enforce constraints such as primary * layer covering entire screen, since that is something we want * to allow (on hw that supports it). For hw that does not, it * should be checked in driver's crtc->atomic_check() vfunc. * * TODO: Add generic modeset state checks once we support those. */ if (state->active && !state->enable) { DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n", crtc->base.id); return -EINVAL; } return 0; }
/** * drm_atomic_state_free - free all memory for an atomic state * @state: atomic state to deallocate * * This frees all memory associated with an atomic state, including all the * per-object state for planes, crtcs and connectors. */ void drm_atomic_state_free(struct drm_atomic_state *state) { struct drm_device *dev; struct drm_mode_config *config; if (!state) return; dev = state->dev; config = &dev->mode_config; drm_atomic_state_clear(state); DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state); if (config->funcs->atomic_state_free) { config->funcs->atomic_state_free(state); } else { drm_atomic_state_default_release(state); kfree(state); } }
/** * drm_atomic_get_plane_state - get plane state * @state: global atomic state object * @plane: plane to get state object for * * This function returns the plane state for the given plane, allocating it if * needed. It will also grab the relevant plane lock to make sure that the state * is consistent. * * Returns: * * Either the allocated state or the error code encoded into the pointer. When * the error is EDEADLK then the w/w mutex code has detected a deadlock and the * entire atomic sequence must be restarted. All other errors are fatal. */ struct drm_plane_state * drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane) { int ret, index; struct drm_plane_state *plane_state; index = drm_plane_index(plane); if (state->plane_states[index]) return state->plane_states[index]; ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx); if (ret) return ERR_PTR(ret); plane_state = plane->funcs->atomic_duplicate_state(plane); if (!plane_state) return ERR_PTR(-ENOMEM); state->plane_states[index] = plane_state; 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); if (plane_state->crtc) { struct drm_crtc_state *crtc_state; crtc_state = drm_atomic_get_crtc_state(state, plane_state->crtc); if (IS_ERR(crtc_state)) return ERR_CAST(crtc_state); } return plane_state; }
/** * drm_atomic_plane_check - check plane state * @old_plane_state: old plane state to check * @new_plane_state: new plane state to check * * Provides core sanity checks for plane state. * * RETURNS: * Zero on success, error code on failure */ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, const struct drm_plane_state *new_plane_state) { struct drm_plane *plane = new_plane_state->plane; struct drm_crtc *crtc = new_plane_state->crtc; const struct drm_framebuffer *fb = new_plane_state->fb; unsigned int fb_width, fb_height; struct drm_mode_rect *clips; uint32_t num_clips; int ret; /* either *both* CRTC and FB must be set, or neither */ if (crtc && !fb) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] CRTC set but no FB\n", plane->base.id, plane->name); return -EINVAL; } else if (fb && !crtc) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] FB set but no CRTC\n", plane->base.id, plane->name); return -EINVAL; } /* if disabled, we don't care about the rest of the state: */ if (!crtc) return 0; /* Check whether this plane is usable on this CRTC */ if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { DRM_DEBUG_ATOMIC("Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n", crtc->base.id, crtc->name, plane->base.id, plane->name); return -EINVAL; } /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, fb->format->format, fb->modifier); if (ret) { struct drm_format_name_buf format_name; DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid pixel format %s, modifier 0x%llx\n", plane->base.id, plane->name, drm_get_format_name(fb->format->format, &format_name), fb->modifier); return ret; } /* Give drivers some help against integer overflows */ if (new_plane_state->crtc_w > INT_MAX || new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w || new_plane_state->crtc_h > INT_MAX || new_plane_state->crtc_y > INT_MAX - (int32_t) new_plane_state->crtc_h) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid CRTC coordinates %ux%u+%d+%d\n", plane->base.id, plane->name, new_plane_state->crtc_w, new_plane_state->crtc_h, new_plane_state->crtc_x, new_plane_state->crtc_y); return -ERANGE; } fb_width = fb->width << 16; fb_height = fb->height << 16; /* Make sure source coordinates are inside the fb. */ if (new_plane_state->src_w > fb_width || new_plane_state->src_x > fb_width - new_plane_state->src_w || new_plane_state->src_h > fb_height || new_plane_state->src_y > fb_height - new_plane_state->src_h) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid source coordinates " "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", plane->base.id, plane->name, new_plane_state->src_w >> 16, ((new_plane_state->src_w & 0xffff) * 15625) >> 10, new_plane_state->src_h >> 16, ((new_plane_state->src_h & 0xffff) * 15625) >> 10, new_plane_state->src_x >> 16, ((new_plane_state->src_x & 0xffff) * 15625) >> 10, new_plane_state->src_y >> 16, ((new_plane_state->src_y & 0xffff) * 15625) >> 10, fb->width, fb->height); return -ENOSPC; }
/** * drm_atomic_state_default_clear - clear base atomic state * @state: atomic state * * Default implementation for clearing atomic state. * This should only be used by drivers which are still subclassing * &drm_atomic_state and haven't switched to &drm_private_state yet. */ void drm_atomic_state_default_clear(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_mode_config *config = &dev->mode_config; int i; DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state); for (i = 0; i < state->num_connector; i++) { struct drm_connector *connector = state->connectors[i].ptr; if (!connector) continue; connector->funcs->atomic_destroy_state(connector, state->connectors[i].state); state->connectors[i].ptr = NULL; state->connectors[i].state = NULL; state->connectors[i].old_state = NULL; state->connectors[i].new_state = NULL; drm_connector_put(connector); } for (i = 0; i < config->num_crtc; i++) { struct drm_crtc *crtc = state->crtcs[i].ptr; if (!crtc) continue; crtc->funcs->atomic_destroy_state(crtc, state->crtcs[i].state); state->crtcs[i].ptr = NULL; state->crtcs[i].state = NULL; state->crtcs[i].old_state = NULL; state->crtcs[i].new_state = NULL; if (state->crtcs[i].commit) { drm_crtc_commit_put(state->crtcs[i].commit); state->crtcs[i].commit = NULL; } } for (i = 0; i < config->num_total_plane; i++) { struct drm_plane *plane = state->planes[i].ptr; if (!plane) continue; plane->funcs->atomic_destroy_state(plane, state->planes[i].state); state->planes[i].ptr = NULL; state->planes[i].state = NULL; state->planes[i].old_state = NULL; state->planes[i].new_state = NULL; } for (i = 0; i < state->num_private_objs; i++) { struct drm_private_obj *obj = state->private_objs[i].ptr; obj->funcs->atomic_destroy_state(obj, state->private_objs[i].state); state->private_objs[i].ptr = NULL; state->private_objs[i].state = NULL; state->private_objs[i].old_state = NULL; state->private_objs[i].new_state = NULL; } state->num_private_objs = 0; if (state->fake_commit) { drm_crtc_commit_put(state->fake_commit); state->fake_commit = NULL; } }