mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	drm: Introduce helper for replacing blob properties
Introduce a common helper for the pattern of: - allocate new blob property - potentially free old blob property - replace content of indicative property with new blob ID - change member pointer on modeset object Signed-off-by: Daniel Stone <daniels@collabora.com> Cc: Dave Airlie <airlied@redhat.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> [danvet: Squash in fixup from Daniel for the kerneldoc, reported by 0day builder.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
		
							parent
							
								
									4339ed82b2
								
							
						
					
					
						commit
						d2ed34362a
					
				
					 1 changed files with 106 additions and 49 deletions
				
			
		| 
						 | 
					@ -4238,6 +4238,83 @@ static void drm_property_destroy_blob(struct drm_device *dev,
 | 
				
			||||||
	kfree(blob);
 | 
						kfree(blob);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * drm_property_replace_global_blob - atomically replace existing blob property
 | 
				
			||||||
 | 
					 * @dev: drm device
 | 
				
			||||||
 | 
					 * @replace: location of blob property pointer to be replaced
 | 
				
			||||||
 | 
					 * @length: length of data for new blob, or 0 for no data
 | 
				
			||||||
 | 
					 * @data: content for new blob, or NULL for no data
 | 
				
			||||||
 | 
					 * @obj_holds_id: optional object for property holding blob ID
 | 
				
			||||||
 | 
					 * @prop_holds_id: optional property holding blob ID
 | 
				
			||||||
 | 
					 * @return 0 on success or error on failure
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function will atomically replace a global property in the blob list,
 | 
				
			||||||
 | 
					 * optionally updating a property which holds the ID of that property. It is
 | 
				
			||||||
 | 
					 * guaranteed to be atomic: no caller will be allowed to see intermediate
 | 
				
			||||||
 | 
					 * results, and either the entire operation will succeed and clean up the
 | 
				
			||||||
 | 
					 * previous property, or it will fail and the state will be unchanged.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If length is 0 or data is NULL, no new blob will be created, and the holding
 | 
				
			||||||
 | 
					 * property, if specified, will be set to 0.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Access to the replace pointer is assumed to be protected by the caller, e.g.
 | 
				
			||||||
 | 
					 * by holding the relevant modesetting object lock for its parent.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For example, a drm_connector has a 'PATH' property, which contains the ID
 | 
				
			||||||
 | 
					 * of a blob property with the value of the MST path information. Calling this
 | 
				
			||||||
 | 
					 * function with replace pointing to the connector's path_blob_ptr, length and
 | 
				
			||||||
 | 
					 * data set for the new path information, obj_holds_id set to the connector's
 | 
				
			||||||
 | 
					 * base object, and prop_holds_id set to the path property name, will perform
 | 
				
			||||||
 | 
					 * a completely atomic update. The access to path_blob_ptr is protected by the
 | 
				
			||||||
 | 
					 * caller holding a lock on the connector.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int drm_property_replace_global_blob(struct drm_device *dev,
 | 
				
			||||||
 | 
					                                            struct drm_property_blob **replace,
 | 
				
			||||||
 | 
					                                            size_t length,
 | 
				
			||||||
 | 
					                                            const void *data,
 | 
				
			||||||
 | 
					                                            struct drm_mode_object *obj_holds_id,
 | 
				
			||||||
 | 
					                                            struct drm_property *prop_holds_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct drm_property_blob *new_blob = NULL;
 | 
				
			||||||
 | 
						struct drm_property_blob *old_blob = NULL;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						WARN_ON(replace == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						old_blob = *replace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (length && data) {
 | 
				
			||||||
 | 
							new_blob = drm_property_create_blob(dev, length, data);
 | 
				
			||||||
 | 
							if (!new_blob)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* This does not need to be synchronised with blob_lock, as the
 | 
				
			||||||
 | 
						 * get_properties ioctl locks all modesetting objects, and
 | 
				
			||||||
 | 
						 * obj_holds_id must be locked before calling here, so we cannot
 | 
				
			||||||
 | 
						 * have its value out of sync with the list membership modified
 | 
				
			||||||
 | 
						 * below under blob_lock. */
 | 
				
			||||||
 | 
						if (obj_holds_id) {
 | 
				
			||||||
 | 
							ret = drm_object_property_set_value(obj_holds_id,
 | 
				
			||||||
 | 
											    prop_holds_id,
 | 
				
			||||||
 | 
											    new_blob ?
 | 
				
			||||||
 | 
											        new_blob->base.id : 0);
 | 
				
			||||||
 | 
							if (ret != 0)
 | 
				
			||||||
 | 
								goto err_created;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (old_blob)
 | 
				
			||||||
 | 
							drm_property_destroy_blob(dev, old_blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*replace = new_blob;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_created:
 | 
				
			||||||
 | 
						drm_property_destroy_blob(dev, new_blob);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * drm_mode_getblob_ioctl - get the contents of a blob property value
 | 
					 * drm_mode_getblob_ioctl - get the contents of a blob property value
 | 
				
			||||||
 * @dev: DRM device
 | 
					 * @dev: DRM device
 | 
				
			||||||
| 
						 | 
					@ -4287,7 +4364,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * drm_mode_connector_set_path_property - set tile property on connector
 | 
					 * drm_mode_connector_set_path_property - set tile property on connector
 | 
				
			||||||
 * @connector: connector to set property on.
 | 
					 * @connector: connector to set property on.
 | 
				
			||||||
 * @path: path to use for property.
 | 
					 * @path: path to use for property; must not be NULL.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This creates a property to expose to userspace to specify a
 | 
					 * This creates a property to expose to userspace to specify a
 | 
				
			||||||
 * connector path. This is mainly used for DisplayPort MST where
 | 
					 * connector path. This is mainly used for DisplayPort MST where
 | 
				
			||||||
| 
						 | 
					@ -4301,20 +4378,14 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector,
 | 
				
			||||||
					 const char *path)
 | 
										 const char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_device *dev = connector->dev;
 | 
						struct drm_device *dev = connector->dev;
 | 
				
			||||||
	size_t size = strlen(path) + 1;
 | 
					 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connector->path_blob_ptr)
 | 
						ret = drm_property_replace_global_blob(dev,
 | 
				
			||||||
		drm_property_destroy_blob(dev, connector->path_blob_ptr);
 | 
						                                       &connector->path_blob_ptr,
 | 
				
			||||||
 | 
						                                       strlen(path) + 1,
 | 
				
			||||||
	connector->path_blob_ptr = drm_property_create_blob(connector->dev,
 | 
						                                       path,
 | 
				
			||||||
							    size, path);
 | 
						                                       &connector->base,
 | 
				
			||||||
	if (!connector->path_blob_ptr)
 | 
						                                       dev->mode_config.path_property);
 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = drm_object_property_set_value(&connector->base,
 | 
					 | 
				
			||||||
					    dev->mode_config.path_property,
 | 
					 | 
				
			||||||
					    connector->path_blob_ptr->base.id);
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(drm_mode_connector_set_path_property);
 | 
					EXPORT_SYMBOL(drm_mode_connector_set_path_property);
 | 
				
			||||||
| 
						 | 
					@ -4333,16 +4404,16 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property);
 | 
				
			||||||
int drm_mode_connector_set_tile_property(struct drm_connector *connector)
 | 
					int drm_mode_connector_set_tile_property(struct drm_connector *connector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_device *dev = connector->dev;
 | 
						struct drm_device *dev = connector->dev;
 | 
				
			||||||
	int ret, size;
 | 
					 | 
				
			||||||
	char tile[256];
 | 
						char tile[256];
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
	if (connector->tile_blob_ptr)
 | 
					 | 
				
			||||||
		drm_property_destroy_blob(dev, connector->tile_blob_ptr);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!connector->has_tile) {
 | 
						if (!connector->has_tile) {
 | 
				
			||||||
		connector->tile_blob_ptr = NULL;
 | 
							ret  = drm_property_replace_global_blob(dev,
 | 
				
			||||||
		ret = drm_object_property_set_value(&connector->base,
 | 
							                                        &connector->tile_blob_ptr,
 | 
				
			||||||
						    dev->mode_config.tile_property, 0);
 | 
							                                        0,
 | 
				
			||||||
 | 
							                                        NULL,
 | 
				
			||||||
 | 
							                                        &connector->base,
 | 
				
			||||||
 | 
							                                        dev->mode_config.tile_property);
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4351,16 +4422,13 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector)
 | 
				
			||||||
		 connector->num_h_tile, connector->num_v_tile,
 | 
							 connector->num_h_tile, connector->num_v_tile,
 | 
				
			||||||
		 connector->tile_h_loc, connector->tile_v_loc,
 | 
							 connector->tile_h_loc, connector->tile_v_loc,
 | 
				
			||||||
		 connector->tile_h_size, connector->tile_v_size);
 | 
							 connector->tile_h_size, connector->tile_v_size);
 | 
				
			||||||
	size = strlen(tile) + 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
 | 
						ret = drm_property_replace_global_blob(dev,
 | 
				
			||||||
							    size, tile);
 | 
						                                       &connector->tile_blob_ptr,
 | 
				
			||||||
	if (!connector->tile_blob_ptr)
 | 
						                                       strlen(tile) + 1,
 | 
				
			||||||
		return -EINVAL;
 | 
						                                       tile,
 | 
				
			||||||
 | 
						                                       &connector->base,
 | 
				
			||||||
	ret = drm_object_property_set_value(&connector->base,
 | 
						                                       dev->mode_config.tile_property);
 | 
				
			||||||
					    dev->mode_config.tile_property,
 | 
					 | 
				
			||||||
					    connector->tile_blob_ptr->base.id);
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
 | 
					EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
 | 
				
			||||||
| 
						 | 
					@ -4380,33 +4448,22 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 | 
				
			||||||
					    const struct edid *edid)
 | 
										    const struct edid *edid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_device *dev = connector->dev;
 | 
						struct drm_device *dev = connector->dev;
 | 
				
			||||||
	size_t size;
 | 
						size_t size = 0;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* ignore requests to set edid when overridden */
 | 
						/* ignore requests to set edid when overridden */
 | 
				
			||||||
	if (connector->override_edid)
 | 
						if (connector->override_edid)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connector->edid_blob_ptr)
 | 
						if (edid)
 | 
				
			||||||
		drm_property_destroy_blob(dev, connector->edid_blob_ptr);
 | 
							size = EDID_LENGTH + (1 + edid->extensions);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Delete edid, when there is none. */
 | 
					 | 
				
			||||||
	if (!edid) {
 | 
					 | 
				
			||||||
		connector->edid_blob_ptr = NULL;
 | 
					 | 
				
			||||||
		ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size = EDID_LENGTH * (1 + edid->extensions);
 | 
					 | 
				
			||||||
	connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
 | 
					 | 
				
			||||||
							    size, edid);
 | 
					 | 
				
			||||||
	if (!connector->edid_blob_ptr)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = drm_object_property_set_value(&connector->base,
 | 
					 | 
				
			||||||
					       dev->mode_config.edid_property,
 | 
					 | 
				
			||||||
					       connector->edid_blob_ptr->base.id);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = drm_property_replace_global_blob(dev,
 | 
				
			||||||
 | 
										       &connector->edid_blob_ptr,
 | 
				
			||||||
 | 
						                                       size,
 | 
				
			||||||
 | 
						                                       edid,
 | 
				
			||||||
 | 
						                                       &connector->base,
 | 
				
			||||||
 | 
						                                       dev->mode_config.edid_property);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
 | 
					EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue