Hi, I saw your description but please generate the patches against the latest codes at next time. On 4/14/12, Prathyush <prathyush.k@xxxxxxxxxxx> wrote: > With this change, the exynos drm dmabuf module can export and > import dmabuf of gem objects with non-continuous memory. > > The exynos_map_dmabuf function can create SGT of a non-contiguous > buffer by calling dma_get_pages to retrieve the allocated pages > and then maps the SGT to the caller's address space. > > Signed-off-by: Prathyush K <prathyush.k@xxxxxxxxxxx> > --- > drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | 98 > +++++++++++++++++++++++----- > 1 files changed, 81 insertions(+), 17 deletions(-) > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > index cbb6ad4..54b88bd 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > @@ -56,6 +56,59 @@ static void exynos_dmabuf_detach(struct dma_buf *dmabuf, > dma_buf_put(dmabuf); > } > > + Useless newline. > +static struct sg_table *drm_dc_pages_to_sgt(struct page **pages, > + unsigned long n_pages, size_t offset, size_t offset2, dma_addr_t daddr) > +{ > + struct sg_table *sgt; > + struct scatterlist *s; > + int i, j, cur_page, chunks, ret; > + > + sgt = kzalloc(sizeof *sgt, GFP_KERNEL); > + if (!sgt) > + return ERR_PTR(-ENOMEM); > + > + /* compute number of chunks */ > + chunks = 1; > + for (i = 1; i < n_pages; ++i) > + if (pages[i] != pages[i - 1] + 1) > + ++chunks; > + > + ret = sg_alloc_table(sgt, chunks, GFP_KERNEL); > + if (ret) { > + kfree(sgt); > + return ERR_PTR(-ENOMEM); > + } > + > + /* merging chunks and putting them into the scatterlist */ > + cur_page = 0; > + for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { > + size_t size = PAGE_SIZE; > + > + for (j = cur_page + 1; j < n_pages; ++j) { > + if (pages[j] != pages[j - 1] + 1) > + break; > + size += PAGE_SIZE; > + } > + > + /* cut offset if chunk starts at the first page */ > + if (cur_page == 0) > + size -= offset; > + /* cut offset2 if chunk ends at the last page */ > + if (j == n_pages) > + size -= offset2; > + > + sg_set_page(s, pages[cur_page], size, offset); > + s->dma_address = daddr; > + daddr += size; > + offset = 0; > + cur_page = j; > + } > + > + return sgt; > +} This function is almost same as Tomasz one at v4l2. To Tomasz, Can you make it common helper function at common place? > + > + Useless newline too. > static struct sg_table *exynos_map_dmabuf(struct dma_buf_attachment > *attach, > enum dma_data_direction direction) > { > @@ -64,6 +117,8 @@ static struct sg_table *exynos_map_dmabuf(struct > dma_buf_attachment *attach, > struct exynos_drm_gem_buf *buffer; > struct sg_table *sgt; > int ret; > + int size, n_pages; > + struct page **pages = NULL; > > DRM_DEBUG_KMS("%s\n", __FILE__); > > @@ -71,27 +126,37 @@ static struct sg_table *exynos_map_dmabuf(struct > dma_buf_attachment *attach, > > buffer = exynos_gem_obj->buffer; > > - /* TODO. consider physically non-continuous memory with IOMMU. */ > + size = buffer->size; > + n_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; > > - sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); > - if (!sgt) { > - DRM_DEBUG_KMS("failed to allocate sg table.\n"); > - return ERR_PTR(-ENOMEM); > + pages = kmalloc(n_pages * sizeof pages[0], GFP_KERNEL); kcalloc? Thank you, Kyungmin Park > + if (!pages) { > + DRM_DEBUG_KMS("failed to alloc page table\n"); > + return NULL; > } > > - ret = sg_alloc_table(sgt, 1, GFP_KERNEL); > + ret = dma_get_pages(attach->dev, buffer->kvaddr, > + buffer->dma_addr, pages, n_pages); > if (ret < 0) { > - DRM_DEBUG_KMS("failed to allocate scatter list.\n"); > - kfree(sgt); > - sgt = NULL; > - return ERR_PTR(-ENOMEM); > + DRM_DEBUG_KMS("failed to get buffer pages from DMA API\n"); > + return NULL; > } > + if (ret != n_pages) { > + DRM_DEBUG_KMS("failed to get all pages from DMA API\n"); > + return NULL; > + } > + > + sgt = drm_dc_pages_to_sgt(pages, n_pages, 0, 0, buffer->dma_addr); > + if (IS_ERR(sgt)) { > + DRM_DEBUG_KMS("failed to prepare sg table\n"); > + return NULL; > + } > + > + sgt->nents = dma_map_sg(attach->dev, sgt->sgl, > + sgt->orig_nents, DMA_BIDIRECTIONAL); > > - sg_init_table(sgt->sgl, 1); > - sg_dma_len(sgt->sgl) = buffer->size; > - sg_set_page(sgt->sgl, pfn_to_page(PFN_DOWN(buffer->dma_addr)), > - buffer->size, 0); > - sg_dma_address(sgt->sgl) = buffer->dma_addr; > + /* pages are no longer needed */ > + kfree(pages); > > /* > * increase reference count of this buffer. > @@ -303,8 +368,6 @@ int exynos_dmabuf_prime_fd_to_handle(struct drm_device > *drm_dev, > if (ret < 0) > goto fail_handle; > > - /* consider physically non-continuous memory with IOMMU. */ > - > buffer->dma_addr = sg_dma_address(sgt->sgl); > buffer->size = sg_dma_len(sgt->sgl); > > @@ -316,6 +379,7 @@ int exynos_dmabuf_prime_fd_to_handle(struct drm_device > *drm_dev, > atomic_set(&buffer->shared_refcount, 1); > > exynos_gem_obj->base.import_attach = attach; > + exynos_gem_obj->buffer = buffer; > > ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime, > dmabuf, *handle); > -- > 1.7.0.4 > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel