Module Name: src
Committed By: riastradh
Date: Mon Aug 27 15:26:50 UTC 2018
Modified Files:
src/sys/external/bsd/drm2/dist/drm: drm_prime.c
src/sys/external/bsd/drm2/dist/include/drm: drmP.h
src/sys/external/bsd/drm2/drm: drm_gem_cma_helper.c
src/sys/external/bsd/drm2/include/drm: bus_dma_hacks.h
Log Message:
Rework drm prime guts.
- Our faux struct sg_table is now just an array of _pages_, not of
bus dma segments.
- We handle bus dma segments only in the presence of an adult bus dma
tag.
- All bus dma hacks are once again confined to bus_dma_hacks.h, and
more neatly organized:
. bus_dmamem_export_pages translates bus dma segs to vm_page array
. bus_dmamem_import_pages translates vm_page array to bus dma segs
To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/external/bsd/drm2/dist/drm/drm_prime.c
cvs rdiff -u -r1.28 -r1.29 src/sys/external/bsd/drm2/dist/include/drm/drmP.h
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c
cvs rdiff -u -r1.11 -r1.12 \
src/sys/external/bsd/drm2/include/drm/bus_dma_hacks.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/external/bsd/drm2/dist/drm/drm_prime.c
diff -u src/sys/external/bsd/drm2/dist/drm/drm_prime.c:1.4 src/sys/external/bsd/drm2/dist/drm/drm_prime.c:1.5
--- src/sys/external/bsd/drm2/dist/drm/drm_prime.c:1.4 Mon Aug 27 15:26:00 2018
+++ src/sys/external/bsd/drm2/dist/drm/drm_prime.c Mon Aug 27 15:26:50 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: drm_prime.c,v 1.4 2018/08/27 15:26:00 riastradh Exp $ */
+/* $NetBSD: drm_prime.c,v 1.5 2018/08/27 15:26:50 riastradh Exp $ */
/*
* Copyright © 2012 Red Hat
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_prime.c,v 1.4 2018/08/27 15:26:00 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_prime.c,v 1.5 2018/08/27 15:26:50 riastradh Exp $");
#include <linux/export.h>
#include <linux/dma-buf.h>
@@ -40,22 +40,22 @@ __KERNEL_RCSID(0, "$NetBSD: drm_prime.c,
#ifdef __NetBSD__
+#include <drm/bus_dma_hacks.h>
+
/*
- * We use struct sg_table just to pass around an array of
- * bus_dma_segment_t from one device to another in drm prime. Since
- * this is _not_ a complete implementation of Linux's sg table
- * abstraction (e.g., it does not remember DMA addresses and RAM pages
- * separately, and it doesn't support the nested chained iteration of
- * Linux scatterlists), we isolate it to this file and make all callers
- * go through a few extra subroutines (drm_prime_sg_size,
- * drm_prime_sg_free, &c.) to use it. Don't use this outside drm
- * prime!
+ * We use struct sg_table just to pass around an array of pages from
+ * one device to another in drm prime. Since this is _not_ a complete
+ * implementation of Linux's sg table abstraction (e.g., it does not
+ * remember DMA addresses and RAM pages separately, and it doesn't
+ * support the nested chained iteration of Linux scatterlists), we
+ * isolate it to this file and make all callers go through a few extra
+ * subroutines (drm_prime_sg_size, drm_prime_sg_free, &c.) to use it.
+ * Don't use this outside drm prime!
*/
struct sg_table {
- bus_dma_segment_t *sgt_segs;
- int sgt_nsegs;
- bus_size_t sgt_size;
+ struct vm_page **sgt_pgs;
+ unsigned sgt_npgs;
};
static int
@@ -67,22 +67,19 @@ sg_alloc_table_from_pages(struct sg_tabl
KASSERT(offset == 0);
KASSERT(size == npages << PAGE_SHIFT);
- sgt->sgt_segs = kcalloc(npages, sizeof(sgt->sgt_segs[0]), gfp);
- if (sgt->sgt_segs == NULL)
+ sgt->sgt_pgs = kcalloc(npages, sizeof(sgt->sgt_pgs[0]), gfp);
+ if (sgt->sgt_pgs == NULL)
return -ENOMEM;
- sgt->sgt_nsegs = npages;
- sgt->sgt_size = size;
+ sgt->sgt_npgs = npages;
- for (i = 0; i < npages; i++) {
- sgt->sgt_segs[i].ds_addr = VM_PAGE_TO_PHYS(&pages[i]->p_vmp);
- sgt->sgt_segs[i].ds_len = PAGE_SIZE;
- }
+ for (i = 0; i < npages; i++)
+ sgt->sgt_pgs[i] = &pages[i]->p_vmp;
return 0;
}
static int
-sg_alloc_table_from_pglist(struct sg_table *sgt, struct pglist *pglist,
+sg_alloc_table_from_pglist(struct sg_table *sgt, const struct pglist *pglist,
unsigned npages, bus_size_t offset, bus_size_t size, gfp_t gfp)
{
struct vm_page *pg;
@@ -91,17 +88,15 @@ sg_alloc_table_from_pglist(struct sg_tab
KASSERT(offset == 0);
KASSERT(size == npages << PAGE_SHIFT);
- sgt->sgt_segs = kcalloc(npages, sizeof(sgt->sgt_segs[0]), gfp);
- if (sgt->sgt_segs == NULL)
+ sgt->sgt_pgs = kcalloc(npages, sizeof(sgt->sgt_pgs[0]), gfp);
+ if (sgt->sgt_pgs == NULL)
return -ENOMEM;
- sgt->sgt_nsegs = npages;
- sgt->sgt_size = size;
+ sgt->sgt_npgs = npages;
i = 0;
TAILQ_FOREACH(pg, pglist, pageq.queue) {
KASSERT(i < npages);
- sgt->sgt_segs[i].ds_addr = VM_PAGE_TO_PHYS(pg);
- sgt->sgt_segs[i].ds_len = PAGE_SIZE;
+ sgt->sgt_pgs[i] = pg;
}
KASSERT(i == npages);
@@ -109,25 +104,22 @@ sg_alloc_table_from_pglist(struct sg_tab
}
static int
-sg_alloc_table_from_bus_dmamem(struct sg_table *sgt, bus_dma_segment_t *segs,
- int nsegs, gfp_t gfp)
+sg_alloc_table_from_bus_dmamem(struct sg_table *sgt, bus_dma_tag_t dmat,
+ const bus_dma_segment_t *segs, int nsegs, gfp_t gfp)
{
- int seg;
+ int ret;
KASSERT(nsegs > 0);
- sgt->sgt_segs = kcalloc(nsegs, sizeof(sgt->sgt_segs[0]), gfp);
- if (sgt->sgt_segs == NULL)
+ sgt->sgt_pgs = kcalloc(nsegs, sizeof(sgt->sgt_pgs[0]), gfp);
+ if (sgt->sgt_pgs == NULL)
return -ENOMEM;
- sgt->sgt_nsegs = nsegs;
- sgt->sgt_size = 0;
+ sgt->sgt_npgs = nsegs;
- for (seg = 0; seg < nsegs; seg++) {
- sgt->sgt_segs[seg].ds_addr = segs[seg].ds_addr;
- sgt->sgt_segs[seg].ds_len = segs[seg].ds_len;
- KASSERT(segs[seg].ds_len <= __type_max(bus_size_t) -
- sgt->sgt_size);
- sgt->sgt_size += segs[seg].ds_len;
- }
+ /* XXX errno NetBSD->Linux */
+ ret = -bus_dmamem_export_pages(dmat, segs, nsegs, sgt->sgt_pgs,
+ sgt->sgt_npgs);
+ if (ret)
+ return ret;
return 0;
}
@@ -136,10 +128,9 @@ static void
sg_free_table(struct sg_table *sgt)
{
- kfree(sgt->sgt_segs);
- sgt->sgt_segs = NULL;
- sgt->sgt_nsegs = 0;
- sgt->sgt_size = 0;
+ kfree(sgt->sgt_pgs);
+ sgt->sgt_pgs = NULL;
+ sgt->sgt_npgs = 0;
}
#endif /* __NetBSD__ */
@@ -835,7 +826,8 @@ EXPORT_SYMBOL(drm_prime_pages_to_sg);
#ifdef __NetBSD__
struct sg_table *
-drm_prime_bus_dmamem_to_sg(bus_dma_segment_t *segs, int nsegs)
+drm_prime_bus_dmamem_to_sg(bus_dma_tag_t dmat, const bus_dma_segment_t *segs,
+ int nsegs)
{
struct sg_table *sg;
int ret;
@@ -846,7 +838,8 @@ drm_prime_bus_dmamem_to_sg(bus_dma_segme
goto out;
}
- ret = sg_alloc_table_from_bus_dmamem(sg, segs, nsegs, GFP_KERNEL);
+ ret = sg_alloc_table_from_bus_dmamem(sg, dmat, segs, nsegs,
+ GFP_KERNEL);
if (ret)
goto out;
@@ -884,7 +877,7 @@ bus_size_t
drm_prime_sg_size(struct sg_table *sg)
{
- return sg->sgt_size;
+ return sg->sgt_npgs << PAGE_SHIFT;
}
void
@@ -896,22 +889,43 @@ drm_prime_sg_free(struct sg_table *sg)
}
int
-drm_prime_bus_dmamap_load_sgt(bus_dma_tag_t dmat, bus_dmamap_t map,
- struct sg_table *sgt)
+drm_prime_sg_to_bus_dmamem(bus_dma_tag_t dmat, bus_dma_segment_t *segs,
+ int nsegs, int *rsegs, const struct sg_table *sgt)
{
/* XXX errno NetBSD->Linux */
- return -bus_dmamap_load_raw(dmat, map, sgt->sgt_segs, sgt->sgt_nsegs,
- sgt->sgt_size, BUS_DMA_NOWAIT);
+ return -bus_dmamem_import_pages(dmat, segs, nsegs, rsegs, sgt->sgt_pgs,
+ sgt->sgt_npgs);
}
int
-drm_prime_bus_dmamem_map(bus_dma_tag_t dmat, struct sg_table *sgt, void **kvap,
- int flags)
+drm_prime_bus_dmamap_load_sgt(bus_dma_tag_t dmat, bus_dmamap_t map,
+ struct sg_table *sgt)
{
+ bus_dma_segment_t *segs;
+ bus_size_t size = drm_prime_sg_size(sgt);
+ int nsegs = sgt->sgt_npgs;
+ int ret;
+
+ segs = kcalloc(sgt->sgt_npgs, sizeof(segs[0]), GFP_KERNEL);
+ if (segs == NULL) {
+ ret = -ENOMEM;
+ goto out0;
+ }
+
+ ret = drm_prime_sg_to_bus_dmamem(dmat, segs, nsegs, &nsegs, sgt);
+ if (ret)
+ goto out1;
+ KASSERT(nsegs <= sgt->sgt_npgs);
+
+ /* XXX errno NetBSD->Linux */
+ ret = -bus_dmamap_load_raw(dmat, map, segs, nsegs, size,
+ BUS_DMA_NOWAIT);
+ if (ret)
+ goto out1;
- return -bus_dmamem_map(dmat, sgt->sgt_segs, sgt->sgt_nsegs,
- sgt->sgt_size, kvap, flags);
+out1: kfree(segs);
+out0: return ret;
}
#else /* !__NetBSD__ */
Index: src/sys/external/bsd/drm2/dist/include/drm/drmP.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.28 src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.29
--- src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.28 Mon Aug 27 15:26:00 2018
+++ src/sys/external/bsd/drm2/dist/include/drm/drmP.h Mon Aug 27 15:26:50 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: drmP.h,v 1.28 2018/08/27 15:26:00 riastradh Exp $ */
+/* $NetBSD: drmP.h,v 1.29 2018/08/27 15:26:50 riastradh Exp $ */
/*
* Internal Header for the Direct Rendering Manager
@@ -1182,10 +1182,10 @@ extern int drm_gem_prime_fd_to_handle(st
extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
#ifdef __NetBSD__
-extern int drm_prime_bus_dmamap_load_sgt(bus_dma_tag_t, bus_dmamap_t, struct sg_table *);
-extern int drm_prime_bus_dmamem_map(bus_dma_tag_t, struct sg_table *, void **, int);
-extern struct sg_table *drm_prime_bus_dmamem_to_sg(bus_dma_segment_t *, int);
+extern struct sg_table *drm_prime_bus_dmamem_to_sg(bus_dma_tag_t, const bus_dma_segment_t *, int);
extern struct sg_table *drm_prime_pglist_to_sg(struct pglist *, unsigned);
+extern int drm_prime_sg_to_bus_dmamem(bus_dma_tag_t, bus_dma_segment_t *, int, int *, const struct sg_table *);
+extern int drm_prime_bus_dmamap_load_sgt(bus_dma_tag_t, bus_dmamap_t, struct sg_table *);
extern bus_size_t drm_prime_sg_size(struct sg_table *);
extern void drm_prime_sg_free(struct sg_table *);
#else
Index: src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c
diff -u src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c:1.3 src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c:1.4
--- src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c:1.3 Mon Aug 27 15:26:16 2018
+++ src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c Mon Aug 27 15:26:50 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: drm_gem_cma_helper.c,v 1.3 2018/08/27 15:26:16 riastradh Exp $ */
+/* $NetBSD: drm_gem_cma_helper.c,v 1.4 2018/08/27 15:26:50 riastradh Exp $ */
/*-
* Copyright (c) 2015-2017 Jared McNeill <[email protected]>
@@ -27,15 +27,16 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_gem_cma_helper.c,v 1.3 2018/08/27 15:26:16 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_gem_cma_helper.c,v 1.4 2018/08/27 15:26:50 riastradh Exp $");
#include <drm/drmP.h>
#include <drm/drm_gem_cma_helper.h>
#include <uvm/uvm.h>
-struct drm_gem_cma_object *
-drm_gem_cma_create(struct drm_device *ddev, size_t size)
+static struct drm_gem_cma_object *
+drm_gem_cma_create_internal(struct drm_device *ddev, size_t size,
+ struct sg_table *sgt)
{
struct drm_gem_cma_object *obj;
int error, nsegs;
@@ -44,8 +45,13 @@ drm_gem_cma_create(struct drm_device *dd
obj->dmat = ddev->bus_dmat;
obj->dmasize = size;
- error = bus_dmamem_alloc(obj->dmat, obj->dmasize, PAGE_SIZE, 0,
- obj->dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
+ if (sgt) {
+ error = -drm_prime_sg_to_bus_dmamem(obj->dmat, obj->dmasegs, 1,
+ &nsegs, sgt);
+ } else {
+ error = bus_dmamem_alloc(obj->dmat, obj->dmasize, PAGE_SIZE, 0,
+ obj->dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
+ }
if (error)
goto failed;
error = bus_dmamem_map(obj->dmat, obj->dmasegs, nsegs,
@@ -61,7 +67,8 @@ drm_gem_cma_create(struct drm_device *dd
if (error)
goto destroy;
- memset(obj->vaddr, 0, obj->dmasize);
+ if (!sgt)
+ memset(obj->vaddr, 0, obj->dmasize);
drm_gem_private_object_init(ddev, &obj->base, size);
@@ -79,6 +86,13 @@ failed:
return NULL;
}
+struct drm_gem_cma_object *
+drm_gem_cma_create(struct drm_device *ddev, size_t size)
+{
+
+ return drm_gem_cma_create_internal(ddev, size, NULL);
+}
+
static void
drm_gem_cma_obj_free(struct drm_gem_cma_object *obj)
{
@@ -229,42 +243,19 @@ drm_gem_cma_prime_get_sg_table(struct dr
{
struct drm_gem_cma_object *obj = to_drm_gem_cma_obj(gem_obj);
- return drm_prime_bus_dmamem_to_sg(obj->dmasegs, 1);
+ return drm_prime_bus_dmamem_to_sg(obj->dmat, obj->dmasegs, 1);
}
struct drm_gem_object *
drm_gem_cma_prime_import_sg_table(struct drm_device *ddev,
struct dma_buf_attachment *attach, struct sg_table *sgt)
{
+ size_t size = drm_prime_sg_size(sgt);
struct drm_gem_cma_object *obj;
- int error;
-
- obj = kmem_zalloc(sizeof(*obj), KM_SLEEP);
- obj->dmat = ddev->dmat;
- obj->dmasize = drm_prime_sg_size(sgt);
- error = bus_dmamap_create(obj->dmat, obj->dmasize, 1, obj->dmasize, 0,
- BUS_DMA_WAITOK, &obj->dmamap);
- if (error)
- goto failed;
- /* XXX errno Linux->NetBSD */
- error = -drm_prime_bus_dmamap_load_sgt(obj->dmat, obj->dmamap, sgt);
- if (error)
- goto destroy;
- error = -drm_prime_bus_dmamem_map(obj->dmat, sgt, &obj->vaddr,
- BUS_DMA_WAITOK | BUS_DMA_COHERENT);
- if (error)
- goto unload;
+ obj = drm_gem_cma_create_internal(ddev, size, sgt);
return &obj->base;
-
-unload:
- bus_dmamap_unload(obj->dmat, obj->dmamap);
-destroy:
- bus_dmamap_destroy(obj->dmat, obj->dmamap);
-failed:
- kmem_free(obj, sizeof(*obj));
- return ERR_PTR(-error); /* XXX errno NetBSD->Linux */
}
void *
Index: src/sys/external/bsd/drm2/include/drm/bus_dma_hacks.h
diff -u src/sys/external/bsd/drm2/include/drm/bus_dma_hacks.h:1.11 src/sys/external/bsd/drm2/include/drm/bus_dma_hacks.h:1.12
--- src/sys/external/bsd/drm2/include/drm/bus_dma_hacks.h:1.11 Mon Aug 27 15:11:58 2018
+++ src/sys/external/bsd/drm2/include/drm/bus_dma_hacks.h Mon Aug 27 15:26:50 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: bus_dma_hacks.h,v 1.11 2018/08/27 15:11:58 riastradh Exp $ */
+/* $NetBSD: bus_dma_hacks.h,v 1.12 2018/08/27 15:26:50 riastradh Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -43,9 +43,11 @@
#if defined(__i386__) || defined(__x86_64__)
# include <x86/bus_private.h>
# include <x86/machdep.h>
-# define PHYS_TO_BUS_MEM(dmat, paddr) (paddr)
+# define PHYS_TO_BUS_MEM(dmat, paddr) ((bus_addr_t)(paddr))
+# define BUS_MEM_TO_PHYS(dmat, baddr) ((paddr_t)(baddr))
#elif defined(__arm__) || defined(__aarch64__)
-# define PHYS_TO_BUS_MEM(dmat, paddr) (paddr)
+# define PHYS_TO_BUS_MEM(dmat, paddr) ((bus_addr_t)(paddr))
+# define BUS_MEM_TO_PHYS(dmat, baddr) ((paddr_t)(baddr))
#elif defined(__powerpc__)
#else
# error DRM GEM/TTM need new MI bus_dma APIs! Halp!
@@ -113,4 +115,102 @@ out: kmem_free(segs, (nsegs * sizeof(seg
return error;
}
+static inline int
+bus_dmamap_load_pgarray(bus_dma_tag_t tag, bus_dmamap_t map,
+ struct vm_page **pgs, unsigned npgs, bus_size_t size, int flags)
+{
+ km_flag_t kmflags;
+ bus_dma_segment_t *segs;
+ unsigned i;
+ int error;
+
+ KASSERT((int)npgs <= (SIZE_MAX / sizeof(segs[0])));
+ switch (flags & (BUS_DMA_WAITOK|BUS_DMA_NOWAIT)) {
+ case BUS_DMA_WAITOK: kmflags = KM_SLEEP; break;
+ case BUS_DMA_NOWAIT: kmflags = KM_NOSLEEP; break;
+ default: panic("invalid flags: %d", flags);
+ }
+ segs = kmem_alloc((npgs * sizeof(segs[0])), kmflags);
+ if (segs == NULL)
+ return ENOMEM;
+
+ for (i = 0; i < npgs; i++) {
+ paddr_t paddr = VM_PAGE_TO_PHYS(pgs[i]);
+ bus_addr_t baddr = PHYS_TO_BUS_MEM(tag, paddr);
+
+ segs[i].ds_addr = baddr;
+ segs[i].ds_len = PAGE_SIZE;
+ }
+
+ error = bus_dmamap_load_raw(tag, map, segs, npgs, size, flags);
+ if (error)
+ goto fail0;
+
+ /* Success! */
+ error = 0;
+ goto out;
+
+fail1: __unused
+ bus_dmamap_unload(tag, map);
+fail0: KASSERT(error);
+out: kmem_free(segs, (npgs * sizeof(segs[0])));
+ return error;
+}
+
+static inline int
+bus_dmamem_export_pages(bus_dma_tag_t dmat, const bus_dma_segment_t *segs,
+ int nsegs, struct vm_page **pgs, unsigned npgs)
+{
+ int seg;
+ unsigned i;
+
+ i = 0;
+ for (seg = 0; seg < nsegs; seg++) {
+ bus_addr_t baddr = segs[i].ds_addr;
+ bus_size_t len = segs[i].ds_len;
+
+ while (len >= PAGE_SIZE) {
+ paddr_t paddr = BUS_MEM_TO_PHYS(dmat, baddr);
+
+ KASSERT(i < npgs);
+ pgs[i++] = PHYS_TO_VM_PAGE(paddr);
+
+ baddr += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ }
+ KASSERT(len == 0);
+ }
+ KASSERT(i == npgs);
+
+ return 0;
+}
+
+static inline int
+bus_dmamem_import_pages(bus_dma_tag_t dmat, bus_dma_segment_t *segs,
+ int nsegs, int *rsegs, struct vm_page *const *pgs, unsigned npgs)
+{
+ int seg;
+ unsigned i;
+
+ seg = 0;
+ for (i = 0; i < npgs; i++) {
+ paddr_t paddr = VM_PAGE_TO_PHYS(pgs[i]);
+ bus_addr_t baddr = PHYS_TO_BUS_MEM(dmat, paddr);
+
+ if (seg > 0 && segs[seg - 1].ds_addr + PAGE_SIZE == baddr) {
+ segs[seg - 1].ds_len += PAGE_SIZE;
+ } else {
+ KASSERT(seg < nsegs);
+ segs[seg].ds_addr = baddr;
+ segs[seg].ds_len = PAGE_SIZE;
+ seg++;
+ KASSERT(seg <= nsegs);
+ }
+ }
+ KASSERT(seg <= nsegs);
+ *rsegs = seg;
+
+ return 0;
+}
+
#endif /* _DRM_BUS_DMA_HACKS_H_ */