diff options
Diffstat (limited to 'drivers/dma-buf/dma-buf.c')
| -rw-r--r-- | drivers/dma-buf/dma-buf.c | 124 | 
1 files changed, 96 insertions, 28 deletions
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 433d91d710e4..ce41cd9b758a 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -45,10 +45,10 @@ static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)  	size_t ret = 0;  	dmabuf = dentry->d_fsdata; -	mutex_lock(&dmabuf->lock); +	dma_resv_lock(dmabuf->resv, NULL);  	if (dmabuf->name)  		ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN); -	mutex_unlock(&dmabuf->lock); +	dma_resv_unlock(dmabuf->resv);  	return dynamic_dname(dentry, buffer, buflen, "/%s:%s",  			     dentry->d_name.name, ret > 0 ? name : ""); @@ -334,7 +334,7 @@ static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)  	if (IS_ERR(name))  		return PTR_ERR(name); -	mutex_lock(&dmabuf->lock); +	dma_resv_lock(dmabuf->resv, NULL);  	if (!list_empty(&dmabuf->attachments)) {  		ret = -EBUSY;  		kfree(name); @@ -344,7 +344,7 @@ static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)  	dmabuf->name = name;  out_unlock: -	mutex_unlock(&dmabuf->lock); +	dma_resv_unlock(dmabuf->resv);  	return ret;  } @@ -403,10 +403,10 @@ static void dma_buf_show_fdinfo(struct seq_file *m, struct file *file)  	/* Don't count the temporary reference taken inside procfs seq_show */  	seq_printf(m, "count:\t%ld\n", file_count(dmabuf->file) - 1);  	seq_printf(m, "exp_name:\t%s\n", dmabuf->exp_name); -	mutex_lock(&dmabuf->lock); +	dma_resv_lock(dmabuf->resv, NULL);  	if (dmabuf->name)  		seq_printf(m, "name:\t%s\n", dmabuf->name); -	mutex_unlock(&dmabuf->lock); +	dma_resv_unlock(dmabuf->resv);  }  static const struct file_operations dma_buf_fops = { @@ -415,9 +415,7 @@ static const struct file_operations dma_buf_fops = {  	.llseek		= dma_buf_llseek,  	.poll		= dma_buf_poll,  	.unlocked_ioctl	= dma_buf_ioctl, -#ifdef CONFIG_COMPAT -	.compat_ioctl	= dma_buf_ioctl, -#endif +	.compat_ioctl	= compat_ptr_ioctl,  	.show_fdinfo	= dma_buf_show_fdinfo,  }; @@ -525,6 +523,10 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)  		return ERR_PTR(-EINVAL);  	} +	if (WARN_ON(exp_info->ops->cache_sgt_mapping && +		    exp_info->ops->dynamic_mapping)) +		return ERR_PTR(-EINVAL); +  	if (!try_module_get(exp_info->owner))  		return ERR_PTR(-ENOENT); @@ -645,10 +647,11 @@ void dma_buf_put(struct dma_buf *dmabuf)  EXPORT_SYMBOL_GPL(dma_buf_put);  /** - * dma_buf_attach - Add the device to dma_buf's attachments list; optionally, + * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list; optionally,   * calls attach() of dma_buf_ops to allow device-specific attach functionality - * @dmabuf:	[in]	buffer to attach device to. - * @dev:	[in]	device to be attached. + * @dmabuf:		[in]	buffer to attach device to. + * @dev:		[in]	device to be attached. + * @dynamic_mapping:	[in]	calling convention for map/unmap   *   * Returns struct dma_buf_attachment pointer for this attachment. Attachments   * must be cleaned up by calling dma_buf_detach(). @@ -662,8 +665,9 @@ EXPORT_SYMBOL_GPL(dma_buf_put);   * accessible to @dev, and cannot be moved to a more suitable place. This is   * indicated with the error code -EBUSY.   */ -struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, -					  struct device *dev) +struct dma_buf_attachment * +dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, +		       bool dynamic_mapping)  {  	struct dma_buf_attachment *attach;  	int ret; @@ -677,24 +681,68 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,  	attach->dev = dev;  	attach->dmabuf = dmabuf; - -	mutex_lock(&dmabuf->lock); +	attach->dynamic_mapping = dynamic_mapping;  	if (dmabuf->ops->attach) {  		ret = dmabuf->ops->attach(dmabuf, attach);  		if (ret)  			goto err_attach;  	} +	dma_resv_lock(dmabuf->resv, NULL);  	list_add(&attach->node, &dmabuf->attachments); +	dma_resv_unlock(dmabuf->resv); -	mutex_unlock(&dmabuf->lock); +	/* When either the importer or the exporter can't handle dynamic +	 * mappings we cache the mapping here to avoid issues with the +	 * reservation object lock. +	 */ +	if (dma_buf_attachment_is_dynamic(attach) != +	    dma_buf_is_dynamic(dmabuf)) { +		struct sg_table *sgt; + +		if (dma_buf_is_dynamic(attach->dmabuf)) +			dma_resv_lock(attach->dmabuf->resv, NULL); + +		sgt = dmabuf->ops->map_dma_buf(attach, DMA_BIDIRECTIONAL); +		if (!sgt) +			sgt = ERR_PTR(-ENOMEM); +		if (IS_ERR(sgt)) { +			ret = PTR_ERR(sgt); +			goto err_unlock; +		} +		if (dma_buf_is_dynamic(attach->dmabuf)) +			dma_resv_unlock(attach->dmabuf->resv); +		attach->sgt = sgt; +		attach->dir = DMA_BIDIRECTIONAL; +	}  	return attach;  err_attach:  	kfree(attach); -	mutex_unlock(&dmabuf->lock);  	return ERR_PTR(ret); + +err_unlock: +	if (dma_buf_is_dynamic(attach->dmabuf)) +		dma_resv_unlock(attach->dmabuf->resv); + +	dma_buf_detach(dmabuf, attach); +	return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(dma_buf_dynamic_attach); + +/** + * dma_buf_attach - Wrapper for dma_buf_dynamic_attach + * @dmabuf:	[in]	buffer to attach device to. + * @dev:	[in]	device to be attached. + * + * Wrapper to call dma_buf_dynamic_attach() for drivers which still use a static + * mapping. + */ +struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, +					  struct device *dev) +{ +	return dma_buf_dynamic_attach(dmabuf, dev, false);  }  EXPORT_SYMBOL_GPL(dma_buf_attach); @@ -711,15 +759,22 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)  	if (WARN_ON(!dmabuf || !attach))  		return; -	if (attach->sgt) +	if (attach->sgt) { +		if (dma_buf_is_dynamic(attach->dmabuf)) +			dma_resv_lock(attach->dmabuf->resv, NULL); +  		dmabuf->ops->unmap_dma_buf(attach, attach->sgt, attach->dir); -	mutex_lock(&dmabuf->lock); +		if (dma_buf_is_dynamic(attach->dmabuf)) +			dma_resv_unlock(attach->dmabuf->resv); +	} + +	dma_resv_lock(dmabuf->resv, NULL);  	list_del(&attach->node); +	dma_resv_unlock(dmabuf->resv);  	if (dmabuf->ops->detach)  		dmabuf->ops->detach(dmabuf, attach); -	mutex_unlock(&dmabuf->lock);  	kfree(attach);  }  EXPORT_SYMBOL_GPL(dma_buf_detach); @@ -749,6 +804,9 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,  	if (WARN_ON(!attach || !attach->dmabuf))  		return ERR_PTR(-EINVAL); +	if (dma_buf_attachment_is_dynamic(attach)) +		dma_resv_assert_held(attach->dmabuf->resv); +  	if (attach->sgt) {  		/*  		 * Two mappings with different directions for the same @@ -761,6 +819,9 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,  		return attach->sgt;  	} +	if (dma_buf_is_dynamic(attach->dmabuf)) +		dma_resv_assert_held(attach->dmabuf->resv); +  	sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);  	if (!sg_table)  		sg_table = ERR_PTR(-ENOMEM); @@ -793,9 +854,15 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,  	if (WARN_ON(!attach || !attach->dmabuf || !sg_table))  		return; +	if (dma_buf_attachment_is_dynamic(attach)) +		dma_resv_assert_held(attach->dmabuf->resv); +  	if (attach->sgt == sg_table)  		return; +	if (dma_buf_is_dynamic(attach->dmabuf)) +		dma_resv_assert_held(attach->dmabuf->resv); +  	attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction);  }  EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); @@ -1171,13 +1238,10 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)  		   "size", "flags", "mode", "count", "ino");  	list_for_each_entry(buf_obj, &db_list.head, list_node) { -		ret = mutex_lock_interruptible(&buf_obj->lock); -		if (ret) { -			seq_puts(s, -				 "\tERROR locking buffer object: skipping\n"); -			continue; -		} +		ret = dma_resv_lock_interruptible(buf_obj->resv, NULL); +		if (ret) +			goto error_unlock;  		seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\n",  				buf_obj->size, @@ -1223,19 +1287,23 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)  			seq_printf(s, "\t%s\n", dev_name(attach_obj->dev));  			attach_count++;  		} +		dma_resv_unlock(buf_obj->resv);  		seq_printf(s, "Total %d devices attached\n\n",  				attach_count);  		count++;  		size += buf_obj->size; -		mutex_unlock(&buf_obj->lock);  	}  	seq_printf(s, "\nTotal %d objects, %zu bytes\n", count, size);  	mutex_unlock(&db_list.lock);  	return 0; + +error_unlock: +	mutex_unlock(&db_list.lock); +	return ret;  }  DEFINE_SHOW_ATTRIBUTE(dma_buf_debug);  |