Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 345554
b: refs/heads/master
c: 8de9e41
h: refs/heads/master
v: v3
  • Loading branch information
Dave Airlie committed Dec 6, 2012
1 parent 00d4979 commit 1e74d48
Show file tree
Hide file tree
Showing 31 changed files with 1,470 additions and 638 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 584955632841c069678833f3320b4f6d21a8215e
refs/heads/master: 8de9e417757fb9f130f55a38f4ee7027b60de1c7
9 changes: 9 additions & 0 deletions trunk/Documentation/DMA-attributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,12 @@ transferred to 'device' domain. This attribute can be also used for
dma_unmap_{single,page,sg} functions family to force buffer to stay in
device domain after releasing a mapping for it. Use this attribute with
care!

DMA_ATTR_FORCE_CONTIGUOUS
-------------------------

By default DMA-mapping subsystem is allowed to assemble the buffer
allocated by dma_alloc_attrs() function from individual pages if it can
be mapped as contiguous chunk into device dma address space. By
specifing this attribute the allocated buffer is forced to be contiguous
also in physical memory.
41 changes: 33 additions & 8 deletions trunk/arch/arm/mm/dma-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,8 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,
spin_unlock_irqrestore(&mapping->lock, flags);
}

static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
gfp_t gfp, struct dma_attrs *attrs)
{
struct page **pages;
int count = size >> PAGE_SHIFT;
Expand All @@ -1050,6 +1051,23 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t
if (!pages)
return NULL;

if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs))
{
unsigned long order = get_order(size);
struct page *page;

page = dma_alloc_from_contiguous(dev, count, order);
if (!page)
goto error;

__dma_clear_buffer(page, size);

for (i = 0; i < count; i++)
pages[i] = page + i;

return pages;
}

while (count) {
int j, order = __fls(count);

Expand Down Expand Up @@ -1083,14 +1101,21 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t
return NULL;
}

static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size)
static int __iommu_free_buffer(struct device *dev, struct page **pages,
size_t size, struct dma_attrs *attrs)
{
int count = size >> PAGE_SHIFT;
int array_size = count * sizeof(struct page *);
int i;
for (i = 0; i < count; i++)
if (pages[i])
__free_pages(pages[i], 0);

if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) {
dma_release_from_contiguous(dev, pages[0], count);
} else {
for (i = 0; i < count; i++)
if (pages[i])
__free_pages(pages[i], 0);
}

if (array_size <= PAGE_SIZE)
kfree(pages);
else
Expand Down Expand Up @@ -1252,7 +1277,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
if (gfp & GFP_ATOMIC)
return __iommu_alloc_atomic(dev, size, handle);

pages = __iommu_alloc_buffer(dev, size, gfp);
pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
if (!pages)
return NULL;

Expand All @@ -1273,7 +1298,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
err_mapping:
__iommu_remove_mapping(dev, *handle, size);
err_buffer:
__iommu_free_buffer(dev, pages, size);
__iommu_free_buffer(dev, pages, size, attrs);
return NULL;
}

Expand Down Expand Up @@ -1329,7 +1354,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
}

__iommu_remove_mapping(dev, handle, size);
__iommu_free_buffer(dev, pages, size);
__iommu_free_buffer(dev, pages, size, attrs);
}

static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/gpu/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,8 @@ void drm_vblank_off(struct drm_device *dev, int crtc)

/* Send any queued vblank events, lest the natives grow disquiet */
seq = drm_vblank_count_and_time(dev, crtc, &now);

spin_lock(&dev->event_lock);
list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
if (e->pipe != crtc)
continue;
Expand All @@ -1031,6 +1033,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
drm_vblank_put(dev, e->pipe);
send_vblank_event(dev, e, seq, &now);
}
spin_unlock(&dev->event_lock);

spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
Expand Down
6 changes: 6 additions & 0 deletions trunk/drivers/gpu/drm/exynos/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ config DRM_EXYNOS
Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm.

config DRM_EXYNOS_IOMMU
bool "EXYNOS DRM IOMMU Support"
depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
help
Choose this option if you want to use IOMMU feature for DRM.

config DRM_EXYNOS_DMABUF
bool "EXYNOS DRM DMABUF"
depends on DRM_EXYNOS
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/gpu/drm/exynos/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
exynos_drm_plane.o

exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
Expand Down
94 changes: 25 additions & 69 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,73 +33,42 @@
static int lowlevel_buffer_allocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
dma_addr_t start_addr;
unsigned int npages, i = 0;
struct scatterlist *sgl;
int ret = 0;
enum dma_attr attr = DMA_ATTR_FORCE_CONTIGUOUS;

DRM_DEBUG_KMS("%s\n", __FILE__);

if (IS_NONCONTIG_BUFFER(flags)) {
DRM_DEBUG_KMS("not support allocation type.\n");
return -EINVAL;
}

if (buf->dma_addr) {
DRM_DEBUG_KMS("already allocated.\n");
return 0;
}

if (buf->size >= SZ_1M) {
npages = buf->size >> SECTION_SHIFT;
buf->page_size = SECTION_SIZE;
} else if (buf->size >= SZ_64K) {
npages = buf->size >> 16;
buf->page_size = SZ_64K;
} else {
npages = buf->size >> PAGE_SHIFT;
buf->page_size = PAGE_SIZE;
}
init_dma_attrs(&buf->dma_attrs);

buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!buf->sgt) {
DRM_ERROR("failed to allocate sg table.\n");
return -ENOMEM;
}
if (flags & EXYNOS_BO_NONCONTIG)
attr = DMA_ATTR_WRITE_COMBINE;

ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
if (ret < 0) {
DRM_ERROR("failed to initialize sg table.\n");
kfree(buf->sgt);
buf->sgt = NULL;
return -ENOMEM;
}
dma_set_attr(attr, &buf->dma_attrs);

buf->kvaddr = dma_alloc_writecombine(dev->dev, buf->size,
&buf->dma_addr, GFP_KERNEL);
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");
ret = -ENOMEM;
goto err1;
return -ENOMEM;
}

buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
if (!buf->pages) {
DRM_ERROR("failed to allocate pages.\n");
buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!buf->sgt) {
DRM_ERROR("failed to allocate sg table.\n");
ret = -ENOMEM;
goto err2;
goto err_free_attrs;
}

sgl = buf->sgt->sgl;
start_addr = buf->dma_addr;

while (i < npages) {
buf->pages[i] = phys_to_page(start_addr);
sg_set_page(sgl, buf->pages[i], buf->page_size, 0);
sg_dma_address(sgl) = start_addr;
start_addr += buf->page_size;
sgl = sg_next(sgl);
i++;
ret = dma_get_sgtable(dev->dev, buf->sgt, buf->kvaddr, buf->dma_addr,
buf->size);
if (ret < 0) {
DRM_ERROR("failed to get sgtable.\n");
goto err_free_sgt;
}

DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
Expand All @@ -108,14 +77,14 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
buf->size);

return ret;
err2:
dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr);
buf->dma_addr = (dma_addr_t)NULL;
err1:
sg_free_table(buf->sgt);

err_free_sgt:
kfree(buf->sgt);
buf->sgt = NULL;
err_free_attrs:
dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;

return ret;
}
Expand All @@ -125,16 +94,6 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
{
DRM_DEBUG_KMS("%s.\n", __FILE__);

/*
* release only physically continuous memory and
* non-continuous memory would be released by exynos
* gem framework.
*/
if (IS_NONCONTIG_BUFFER(flags)) {
DRM_DEBUG_KMS("not support allocation type.\n");
return;
}

if (!buf->dma_addr) {
DRM_DEBUG_KMS("dma_addr is invalid.\n");
return;
Expand All @@ -150,11 +109,8 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
kfree(buf->sgt);
buf->sgt = NULL;

kfree(buf->pages);
buf->pages = NULL;

dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr);
dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;
}

Expand Down
4 changes: 2 additions & 2 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
void exynos_drm_fini_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer);

/* allocate physical memory region and setup sgt and pages. */
/* allocate physical memory region and setup sgt. */
int exynos_drm_alloc_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buf,
unsigned int flags);

/* release physical memory region, sgt and pages. */
/* release physical memory region, and sgt. */
void exynos_drm_free_buf(struct drm_device *dev,
unsigned int flags,
struct exynos_drm_gem_buf *buffer);
Expand Down
5 changes: 5 additions & 0 deletions trunk/drivers/gpu/drm/exynos/exynos_drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,16 +236,21 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
goto out;
}

spin_lock_irq(&dev->event_lock);
list_add_tail(&event->base.link,
&dev_priv->pageflip_event_list);
spin_unlock_irq(&dev->event_lock);

crtc->fb = fb;
ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
NULL);
if (ret) {
crtc->fb = old_fb;

spin_lock_irq(&dev->event_lock);
drm_vblank_put(dev, exynos_crtc->pipe);
list_del(&event->base.link);
spin_unlock_irq(&dev->event_lock);

goto out;
}
Expand Down
Loading

0 comments on commit 1e74d48

Please sign in to comment.