diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_gem.c')
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_gem.c | 79 | 
1 files changed, 78 insertions, 1 deletions
| diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 38af6195d959..b0fa17409b66 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -789,7 +789,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr)  			if (omap_obj->flags & OMAP_BO_TILED_MASK) {  				block = tiler_reserve_2d(fmt,  						omap_obj->width, -						omap_obj->height, 0); +						omap_obj->height, PAGE_SIZE);  			} else {  				block = tiler_reserve_1d(obj->size);  			} @@ -851,6 +851,11 @@ static void omap_gem_unpin_locked(struct drm_gem_object *obj)  		return;  	if (refcount_dec_and_test(&omap_obj->dma_addr_cnt)) { +		if (omap_obj->sgt) { +			sg_free_table(omap_obj->sgt); +			kfree(omap_obj->sgt); +			omap_obj->sgt = NULL; +		}  		ret = tiler_unpin(omap_obj->block);  		if (ret) {  			dev_err(obj->dev->dev, @@ -963,6 +968,78 @@ int omap_gem_put_pages(struct drm_gem_object *obj)  	return 0;  } +struct sg_table *omap_gem_get_sg(struct drm_gem_object *obj) +{ +	struct omap_gem_object *omap_obj = to_omap_bo(obj); +	dma_addr_t addr; +	struct sg_table *sgt; +	struct scatterlist *sg; +	unsigned int count, len, stride, i; +	int ret; + +	ret = omap_gem_pin(obj, &addr); +	if (ret) +		return ERR_PTR(ret); + +	mutex_lock(&omap_obj->lock); + +	sgt = omap_obj->sgt; +	if (sgt) +		goto out; + +	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); +	if (!sgt) { +		ret = -ENOMEM; +		goto err_unpin; +	} + +	if (omap_obj->flags & OMAP_BO_TILED_MASK) { +		enum tiler_fmt fmt = gem2fmt(omap_obj->flags); + +		len = omap_obj->width << (int)fmt; +		count = omap_obj->height; +		stride = tiler_stride(fmt, 0); +	} else { +		len = obj->size; +		count = 1; +		stride = 0; +	} + +	ret = sg_alloc_table(sgt, count, GFP_KERNEL); +	if (ret) +		goto err_free; + +	for_each_sg(sgt->sgl, sg, count, i) { +		sg_set_page(sg, phys_to_page(addr), len, offset_in_page(addr)); +		sg_dma_address(sg) = addr; +		sg_dma_len(sg) = len; + +		addr += stride; +	} + +	omap_obj->sgt = sgt; +out: +	mutex_unlock(&omap_obj->lock); +	return sgt; + +err_free: +	kfree(sgt); +err_unpin: +	mutex_unlock(&omap_obj->lock); +	omap_gem_unpin(obj); +	return ERR_PTR(ret); +} + +void omap_gem_put_sg(struct drm_gem_object *obj, struct sg_table *sgt) +{ +	struct omap_gem_object *omap_obj = to_omap_bo(obj); + +	if (WARN_ON(omap_obj->sgt != sgt)) +		return; + +	omap_gem_unpin(obj); +} +  #ifdef CONFIG_DRM_FBDEV_EMULATION  /*   * Get kernel virtual address for CPU access.. this more or less only |