diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_buf.c')
| -rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_buf.c | 79 | 
1 files changed, 53 insertions, 26 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c index 9601bad47a2..57affae9568 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c @@ -3,24 +3,10 @@   * Copyright (c) 2011 Samsung Electronics Co., Ltd.   * Author: Inki Dae <inki.dae@samsung.com>   * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version.   */  #include <drm/drmP.h> @@ -29,6 +15,7 @@  #include "exynos_drm_drv.h"  #include "exynos_drm_gem.h"  #include "exynos_drm_buf.h" +#include "exynos_drm_iommu.h"  static int lowlevel_buffer_allocate(struct drm_device *dev,  		unsigned int flags, struct exynos_drm_gem_buf *buf) @@ -51,7 +38,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,  	 * region will be allocated else physically contiguous  	 * as possible.  	 */ -	if (flags & EXYNOS_BO_CONTIG) +	if (!(flags & EXYNOS_BO_NONCONTIG))  		dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);  	/* @@ -66,14 +53,45 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,  	dma_set_attr(attr, &buf->dma_attrs);  	dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs); -	buf->pages = dma_alloc_attrs(dev->dev, buf->size, -			&buf->dma_addr, GFP_KERNEL, &buf->dma_attrs); -	if (!buf->pages) { -		DRM_ERROR("failed to allocate buffer.\n"); -		return -ENOMEM; +	nr_pages = buf->size >> PAGE_SHIFT; + +	if (!is_drm_iommu_supported(dev)) { +		dma_addr_t start_addr; +		unsigned int i = 0; + +		buf->pages = kzalloc(sizeof(struct page) * nr_pages, +					GFP_KERNEL); +		if (!buf->pages) { +			DRM_ERROR("failed to allocate pages.\n"); +			return -ENOMEM; +		} + +		buf->kvaddr = dma_alloc_attrs(dev->dev, buf->size, +					&buf->dma_addr, GFP_KERNEL, +					&buf->dma_attrs); +		if (!buf->kvaddr) { +			DRM_ERROR("failed to allocate buffer.\n"); +			kfree(buf->pages); +			return -ENOMEM; +		} + +		start_addr = buf->dma_addr; +		while (i < nr_pages) { +			buf->pages[i] = phys_to_page(start_addr); +			start_addr += PAGE_SIZE; +			i++; +		} +	} else { + +		buf->pages = dma_alloc_attrs(dev->dev, buf->size, +					&buf->dma_addr, GFP_KERNEL, +					&buf->dma_attrs); +		if (!buf->pages) { +			DRM_ERROR("failed to allocate buffer.\n"); +			return -ENOMEM; +		}  	} -	nr_pages = buf->size >> PAGE_SHIFT;  	buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);  	if (!buf->sgt) {  		DRM_ERROR("failed to get sg table.\n"); @@ -92,6 +110,9 @@ err_free_attrs:  			(dma_addr_t)buf->dma_addr, &buf->dma_attrs);  	buf->dma_addr = (dma_addr_t)NULL; +	if (!is_drm_iommu_supported(dev)) +		kfree(buf->pages); +  	return ret;  } @@ -114,8 +135,14 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,  	kfree(buf->sgt);  	buf->sgt = NULL; -	dma_free_attrs(dev->dev, buf->size, buf->pages, +	if (!is_drm_iommu_supported(dev)) { +		dma_free_attrs(dev->dev, buf->size, buf->kvaddr, +				(dma_addr_t)buf->dma_addr, &buf->dma_attrs); +		kfree(buf->pages); +	} else +		dma_free_attrs(dev->dev, buf->size, buf->pages,  				(dma_addr_t)buf->dma_addr, &buf->dma_attrs); +  	buf->dma_addr = (dma_addr_t)NULL;  }  |