Merge tag 'drm-misc-next-2020-10-27' of git://anongit.freedesktop.org/drm/drm-misc...
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / drm_prime.c
index 4910c44..187b55e 100644 (file)
@@ -615,6 +615,7 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
 {
        struct drm_gem_object *obj = attach->dmabuf->priv;
        struct sg_table *sgt;
+       int ret;
 
        if (WARN_ON(dir == DMA_NONE))
                return ERR_PTR(-EINVAL);
@@ -626,11 +627,12 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
        if (IS_ERR(sgt))
                return sgt;
 
-       if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
-                             DMA_ATTR_SKIP_CPU_SYNC)) {
+       ret = dma_map_sgtable(attach->dev, sgt, dir,
+                             DMA_ATTR_SKIP_CPU_SYNC);
+       if (ret) {
                sg_free_table(sgt);
                kfree(sgt);
-               sgt = ERR_PTR(-ENOMEM);
+               sgt = ERR_PTR(ret);
        }
 
        return sgt;
@@ -652,8 +654,7 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
        if (!sgt)
                return;
 
-       dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
-                          DMA_ATTR_SKIP_CPU_SYNC);
+       dma_unmap_sgtable(attach->dev, sgt, dir, DMA_ATTR_SKIP_CPU_SYNC);
        sg_free_table(sgt);
        kfree(sgt);
 }
@@ -796,6 +797,7 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
 
 /**
  * drm_prime_pages_to_sg - converts a page array into an sg list
+ * @dev: DRM device
  * @pages: pointer to the array of page pointers to convert
  * @nr_pages: length of the page vector
  *
@@ -808,34 +810,62 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
 struct sg_table *drm_prime_pages_to_sg(struct drm_device *dev,
                                       struct page **pages, unsigned int nr_pages)
 {
-       struct sg_table *sg = NULL;
+       struct sg_table *sg;
+       struct scatterlist *sge;
        size_t max_segment = 0;
-       int ret;
 
        sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
-       if (!sg) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!sg)
+               return ERR_PTR(-ENOMEM);
 
        if (dev)
                max_segment = dma_max_mapping_size(dev->dev);
        if (max_segment == 0 || max_segment > SCATTERLIST_MAX_SEGMENT)
                max_segment = SCATTERLIST_MAX_SEGMENT;
-       ret = __sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
+       sge = __sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
                                          nr_pages << PAGE_SHIFT,
-                                         max_segment, GFP_KERNEL);
-       if (ret)
-               goto out;
-
+                                         max_segment,
+                                         NULL, 0, GFP_KERNEL);
+       if (IS_ERR(sge)) {
+               kfree(sg);
+               sg = ERR_CAST(sge);
+       }
        return sg;
-out:
-       kfree(sg);
-       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(drm_prime_pages_to_sg);
 
 /**
+ * drm_prime_get_contiguous_size - returns the contiguous size of the buffer
+ * @sgt: sg_table describing the buffer to check
+ *
+ * This helper calculates the contiguous size in the DMA address space
+ * of the the buffer described by the provided sg_table.
+ *
+ * This is useful for implementing
+ * &drm_gem_object_funcs.gem_prime_import_sg_table.
+ */
+unsigned long drm_prime_get_contiguous_size(struct sg_table *sgt)
+{
+       dma_addr_t expected = sg_dma_address(sgt->sgl);
+       struct scatterlist *sg;
+       unsigned long size = 0;
+       int i;
+
+       for_each_sgtable_dma_sg(sgt, sg, i) {
+               unsigned int len = sg_dma_len(sg);
+
+               if (!len)
+                       break;
+               if (sg_dma_address(sg) != expected)
+                       break;
+               expected += len;
+               size += len;
+       }
+       return size;
+}
+EXPORT_SYMBOL(drm_prime_get_contiguous_size);
+
+/**
  * drm_gem_prime_export - helper library implementation of the export callback
  * @obj: GEM object to export
  * @flags: flags like DRM_CLOEXEC and DRM_RDWR
@@ -969,45 +999,26 @@ EXPORT_SYMBOL(drm_gem_prime_import);
 int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
                                     dma_addr_t *addrs, int max_entries)
 {
-       unsigned count;
-       struct scatterlist *sg;
-       struct page *page;
-       u32 page_len, page_index;
-       dma_addr_t addr;
-       u32 dma_len, dma_index;
-
-       /*
-        * Scatterlist elements contains both pages and DMA addresses, but
-        * one shoud not assume 1:1 relation between them. The sg->length is
-        * the size of the physical memory chunk described by the sg->page,
-        * while sg_dma_len(sg) is the size of the DMA (IO virtual) chunk
-        * described by the sg_dma_address(sg).
-        */
-       page_index = 0;
-       dma_index = 0;
-       for_each_sg(sgt->sgl, sg, sgt->nents, count) {
-               page_len = sg->length;
-               page = sg_page(sg);
-               dma_len = sg_dma_len(sg);
-               addr = sg_dma_address(sg);
-
-               while (pages && page_len > 0) {
-                       if (WARN_ON(page_index >= max_entries))
+       struct sg_dma_page_iter dma_iter;
+       struct sg_page_iter page_iter;
+       struct page **p = pages;
+       dma_addr_t *a = addrs;
+
+       if (pages) {
+               for_each_sgtable_page(sgt, &page_iter, 0) {
+                       if (WARN_ON(p - pages >= max_entries))
                                return -1;
-                       pages[page_index] = page;
-                       page++;
-                       page_len -= PAGE_SIZE;
-                       page_index++;
+                       *p++ = sg_page_iter_page(&page_iter);
                }
-               while (addrs && dma_len > 0) {
-                       if (WARN_ON(dma_index >= max_entries))
+       }
+       if (addrs) {
+               for_each_sgtable_dma_page(sgt, &dma_iter, 0) {
+                       if (WARN_ON(a - addrs >= max_entries))
                                return -1;
-                       addrs[dma_index] = addr;
-                       addr += PAGE_SIZE;
-                       dma_len -= PAGE_SIZE;
-                       dma_index++;
+                       *a++ = sg_page_iter_dma_address(&dma_iter);
                }
        }
+
        return 0;
 }
 EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays);