summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2009-02-15 19:52:22 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2009-02-15 19:52:22 +0000
commit298391c1d66394b015b45d4bd7c17dfe2c0efb01 (patch)
tree1ff58626152daf6032d1c5ad1488bfc73a110773 /sys/dev
parentb8dbc425f67bab28cab6e652d43332c68d6d0071 (diff)
introduce drm_dmamem_alloc() to allocate dma memory with bus_dma.
The next few commits will convert calls to drm_pci_alloc (which I hate) over to this new api, and convert other handrolled stuff over too. First part of my cleaning up bus_dma useage in drm.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/drm/drmP.h11
-rw-r--r--sys/dev/pci/drm/drm_drv.c61
2 files changed, 72 insertions, 0 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h
index 7b50ea58ab5..c75f60b2fc0 100644
--- a/sys/dev/pci/drm/drmP.h
+++ b/sys/dev/pci/drm/drmP.h
@@ -304,6 +304,14 @@ typedef struct drm_dma_handle {
size_t size;
} drm_dma_handle_t;
+struct drm_dmamem {
+ bus_dmamap_t map;
+ caddr_t kva;
+ bus_size_t size;
+ int nsegs;
+ bus_dma_segment_t segs[1];
+};
+
typedef struct drm_buf_entry {
int buf_size;
int buf_count;
@@ -570,6 +578,9 @@ dev_type_open(drmopen);
dev_type_close(drmclose);
dev_type_mmap(drmmmap);
extern drm_local_map_t *drm_getsarea(struct drm_device *);
+struct drm_dmamem *drm_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
+ int, bus_size_t, int, int);
+void drm_dmamem_free(bus_dma_tag_t, struct drm_dmamem *);
drm_pci_id_list_t *drm_find_description(int , int , drm_pci_id_list_t *);
diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c
index e948965dd93..97f9708872a 100644
--- a/sys/dev/pci/drm/drm_drv.c
+++ b/sys/dev/pci/drm/drm_drv.c
@@ -856,3 +856,64 @@ drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
return 0;
}
+
+struct drm_dmamem *
+drm_dmamem_alloc(bus_dma_tag_t dmat, bus_size_t size, bus_size_t alignment,
+ int nsegments, bus_size_t maxsegsz, int mapflags, int loadflags)
+{
+ struct drm_dmamem *mem;
+ size_t strsize;
+ /*
+ * segs is the last member of the struct since we modify the size
+ * to allow extra segments if more than one are allowed.
+ */
+ strsize = sizeof(*mem) + (sizeof(bus_dma_segment_t) * (nsegments - 1));
+ mem = malloc(strsize, M_DRM, M_NOWAIT | M_ZERO);
+ if (mem == NULL)
+ return (NULL);
+
+ mem->size = size;
+
+ if (bus_dmamap_create(dmat, size, nsegments, maxsegsz, 0,
+ BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mem->map) != 0)
+ goto strfree;
+
+ if (bus_dmamem_alloc(dmat, size, alignment, 0,
+ mem->segs, nsegments, &mem->nsegs, BUS_DMA_NOWAIT) != 0)
+ goto destroy;
+
+ if (bus_dmamem_map(dmat, mem->segs, mem->nsegs, size,
+ &mem->kva, BUS_DMA_NOWAIT | mapflags) != 0)
+ goto free;
+
+ if (bus_dmamap_load(dmat, mem->map, mem->kva, size,
+ NULL, BUS_DMA_NOWAIT | loadflags) != 0)
+ goto unmap;
+ bzero(mem->kva, size);
+
+ return (mem);
+
+unmap:
+ bus_dmamem_unmap(dmat, mem->kva, size);
+free:
+ bus_dmamem_free(dmat, mem->segs, mem->nsegs);
+destroy:
+ bus_dmamap_destroy(dmat, mem->map);
+strfree:
+ free(mem, M_DRM);
+
+ return (NULL);
+}
+
+void
+drm_dmamem_free(bus_dma_tag_t dmat, struct drm_dmamem *mem)
+{
+ if (mem == NULL)
+ return;
+
+ bus_dmamap_unload(dmat, mem->map);
+ bus_dmamem_unmap(dmat, mem->kva, mem->size);
+ bus_dmamem_free(dmat, mem->segs, mem->nsegs);
+ bus_dmamap_destroy(dmat, mem->map);
+ free(mem, M_DRM);
+}