[gPXE-devel] [PATCH 25/33] [linux] UIO-DMA: Initial import of the library
Piotr Jaroszyński
p.jaroszynski at gmail.com
Sun Aug 15 18:59:30 EDT 2010
Imported as-is from the UIO-DMA repository.
Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
src/include/gpxe/linux/uio-dma-ioctl.h | 75 +++++++++++
src/include/gpxe/linux/uio-dma.h | 170 +++++++++++++++++++++++++
src/interface/linux/uio-dma.c | 212 ++++++++++++++++++++++++++++++++
3 files changed, 457 insertions(+), 0 deletions(-)
create mode 100644 src/include/gpxe/linux/uio-dma-ioctl.h
create mode 100644 src/include/gpxe/linux/uio-dma.h
create mode 100644 src/interface/linux/uio-dma.c
diff --git a/src/include/gpxe/linux/uio-dma-ioctl.h b/src/include/gpxe/linux/uio-dma-ioctl.h
new file mode 100644
index 0000000..8f0d3d7
--- /dev/null
+++ b/src/include/gpxe/linux/uio-dma-ioctl.h
@@ -0,0 +1,75 @@
+/**
+ UIO DMA library.
+ Copyright (C) 2009 Qualcomm Inc. All rights reserved.
+ Written by Max Krasnyansky <maxk at qualcommm.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the QUALCOMM Incorporated nor the
+ names of any contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY QUALCOMM AND ANY OTHER CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL QUALCOMM
+ AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UIO_DMA_IOCTL_H
+#define UIO_DMA_IOCTL_H
+
+#include <stdint.h>
+
+/* ioctl defines */
+
+#define UIO_DMA_ALLOC _IOW('U', 200, int)
+struct uio_dma_alloc_req {
+ uint64_t dma_mask;
+ uint16_t memnode;
+ uint16_t cache;
+ uint32_t flags;
+ uint32_t chunk_size;
+ uint32_t chunk_count;
+ uint64_t mmap_offset;
+};
+
+#define UIO_DMA_FREE _IOW('U', 201, int)
+struct uio_dma_free_req {
+ uint64_t mmap_offset;
+};
+
+#define UIO_DMA_MAP _IOW('U', 202, int)
+struct uio_dma_map_req {
+ uint64_t mmap_offset;
+ uint32_t flags;
+ uint32_t devid;
+ uint8_t direction;
+ uint32_t chunk_count;
+ uint32_t chunk_size;
+ uint64_t dmaddr[0];
+};
+
+#define UIO_DMA_UNMAP _IOW('U', 203, int)
+struct uio_dma_unmap_req {
+ uint64_t mmap_offset;
+ uint32_t devid;
+ uint32_t flags;
+ uint8_t direction;
+};
+
+#endif /* UIO_DMA_IOCTL_H */
diff --git a/src/include/gpxe/linux/uio-dma.h b/src/include/gpxe/linux/uio-dma.h
new file mode 100644
index 0000000..366a859
--- /dev/null
+++ b/src/include/gpxe/linux/uio-dma.h
@@ -0,0 +1,170 @@
+/**
+ UIO DMA library.
+ Copyright (C) 2009 Qualcomm Inc. All rights reserved.
+ Written by Max Krasnyansky <maxk at qualcommm.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the QUALCOMM Incorporated nor the
+ names of any contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY QUALCOMM AND ANY OTHER CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL QUALCOMM
+ AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file uio-dma.h
+ * UIO-DMA - DMA support for UIO
+ */
+
+#ifndef UIO_DMA_H
+#define UIO_DMA_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Macro for construction DMA masks
+ * @param n number of non-zero bits
+ */
+#define UIO_DMA_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+
+/* Caching modes */
+enum {
+ UIO_DMA_CACHE_DEFAULT = 0,
+ UIO_DMA_CACHE_DISABLE,
+ UIO_DMA_CACHE_WRITECOMBINE
+};
+
+/* DMA mapping direction */
+enum {
+ UIO_DMA_BIDIRECTIONAL = 0,
+ UIO_DMA_TODEVICE,
+ UIO_DMA_FROMDEVICE
+};
+
+/**
+ * UIO DMA area.
+ */
+struct uio_dma_area {
+ uint8_t *addr;
+ unsigned long mmap_offset;
+ unsigned long size;
+ unsigned long chunk_size;
+ unsigned int chunk_count;
+};
+
+/**
+ * UIO DMA mapping.
+ */
+struct uio_dma_mapping {
+ uint8_t *addr;
+ unsigned long mmap_offset;
+ unsigned long size;
+ unsigned int chunk_count;
+ unsigned int chunk_shift;
+ uint32_t devid;
+ uint8_t direction;
+ uint64_t dmaddr[0];
+};
+
+/**
+ * Open and initialize UIO DMA file descriptor.
+ * @return file descriptor
+ */
+int uio_dma_open();
+
+/**
+ * Close UIO DMA file descriptor.
+ * @param fd file descriptor
+ */
+void uio_dma_close(int fd);
+
+/**
+ * Allocate new DMA area.
+ * @param fd UIO DMA file descriptor
+ * @param size of the area
+ * @param cache caching mode
+ * @param dma_mask mask of the DMA address range
+ * @param memnode memory node to allocate the memory area on
+ */
+struct uio_dma_area *uio_dma_alloc(int fd, unsigned int size,
+ unsigned int cache, uint64_t dma_mask, unsigned int memnode);
+/**
+ * Free DMA area.
+ * @param fd UIO DMA file descriptor
+ * @param pointer to @see uio_dma_area
+ */
+int uio_dma_free(int fd, struct uio_dma_area *a);
+
+/**
+ * Map DMA area to a device.
+ * @param fd UIO DMA file descriptor
+ * @param pointer to @see uio_dma_area
+ * @param devid uio dma device id
+ * @param dir direction
+ * @return pointer to new @see uio_dma_mapping
+ */
+struct uio_dma_mapping * uio_dma_map(int fd, struct uio_dma_area *area, uint32_t devid, unsigned int dir);
+
+/**
+ * Unmap DMA area from a device.
+ * @param fd UIO DMA file descriptor
+ * @param pointer to @see uio_dma_mapping
+ * @return 0 on success, <0 otherwise (sets errno)
+ */
+int uio_dma_unmap(int fd, struct uio_dma_mapping *m);
+
+/**
+ * Map user-space region to the DMA address. Region must belong to the specified
+ * dma mapping. Use this function only when size of the memory region is guaranteed
+ * to be smaller than the chunk_size.
+ * @param m pointer to @see uio_dma_mapping
+ * @param addr pointer to the user-space memory region
+ * @param len length of the memory region
+ * @return dma_addr or 0 if address could not be mapped
+ */
+static inline uint64_t uio_dma_addr(struct uio_dma_mapping *m, uint8_t *addr, unsigned int len)
+{
+ unsigned long chunk, offset, chunk_size;
+
+ chunk_size = (1 << m->chunk_shift);
+ if (len > chunk_size || addr < m->addr || (addr + len) > (m->addr + m->size))
+ return 0;
+
+ offset = addr - m->addr;
+ chunk = offset >> m->chunk_shift;
+ offset = offset & (chunk_size - 1);
+
+ return m->dmaddr[chunk] + offset;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIO_DMA_H */
diff --git a/src/interface/linux/uio-dma.c b/src/interface/linux/uio-dma.c
new file mode 100644
index 0000000..18a7a09
--- /dev/null
+++ b/src/interface/linux/uio-dma.c
@@ -0,0 +1,212 @@
+/**
+ UIO DMA library.
+ Copyright (C) 2009 Qualcomm Inc. All rights reserved.
+ Written by Max Krasnyansky <maxk at qualcommm.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the QUALCOMM Incorporated nor the
+ names of any contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY QUALCOMM AND ANY OTHER CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL QUALCOMM
+ AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+
+#include "uio-dma-ioctl.h"
+#include "uio-dma.h"
+
+static inline int is_po2(unsigned long n)
+{
+ return (n & (n - 1)) == 0;
+}
+
+static unsigned int ulog2(unsigned long n)
+{
+ unsigned int i;
+ for (i = 0; n != 0; n >>= 1, ++i);
+ return i - 1;
+}
+
+static inline unsigned long roundup_po2(unsigned long n)
+{
+ return 1UL << (ulog2(n - 1) + 1);
+}
+
+int uio_dma_open()
+{
+ return open("/dev/uio-dma", O_RDWR);
+}
+
+void uio_dma_close(int fd)
+{
+ close(fd);
+}
+
+struct uio_dma_area *uio_dma_alloc(int fd, unsigned int size,
+ unsigned int cache, uint64_t dma_mask, unsigned int memnode)
+{
+ struct uio_dma_area *da;
+ struct uio_dma_alloc_req areq;
+ struct uio_dma_free_req freq;
+ unsigned int chunk_size;
+ int err;
+
+ da = malloc(sizeof(*da));
+ if (!da)
+ return NULL;
+
+ areq.cache = cache;
+ areq.dma_mask = dma_mask;
+ areq.memnode = memnode;
+ areq.mmap_offset = 0;
+ areq.flags = 0;
+
+ /* Try allocating smallest number of chunks.
+ * We only allocate power of two sized chunks so that we could
+ * avoid division in uio_dma_addr() function. */
+ err = 0;
+ for (chunk_size = roundup_po2(size); chunk_size; chunk_size >>= 1) {
+ areq.chunk_size = chunk_size;
+ areq.chunk_count = (size + chunk_size - 1) / chunk_size;
+ err = ioctl(fd, UIO_DMA_ALLOC, (unsigned long) &areq);
+ if (!err)
+ break;
+ }
+ if (err) {
+ free(da);
+ return NULL;
+ }
+
+ if (!is_po2(areq.chunk_size)) {
+ errno = -EILSEQ;
+ goto failed;
+ }
+
+ da->size = areq.chunk_size * areq.chunk_count;
+ da->chunk_count = areq.chunk_count;
+ da->chunk_size = areq.chunk_size;
+ da->mmap_offset = areq.mmap_offset;
+ da->addr = mmap(NULL, da->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, da->mmap_offset);
+ if (da->addr == MAP_FAILED)
+ goto failed;
+
+ return da;
+
+failed:
+ /* We need to free the area we just requested from the kernel. */
+ err = errno;
+ freq.mmap_offset = da->mmap_offset;
+ ioctl(fd, UIO_DMA_FREE, (unsigned long) &freq);
+ free(da);
+ errno = err;
+ return NULL;
+}
+
+int uio_dma_free(int fd, struct uio_dma_area *da)
+{
+ struct uio_dma_free_req freq;
+ int err;
+
+ munmap(da->addr, da->size);
+
+ freq.mmap_offset = da->mmap_offset;
+ if (ioctl(fd, UIO_DMA_FREE, (unsigned long) &freq) < 0)
+ return -1;
+ free(da);
+ return 0;
+}
+
+struct uio_dma_mapping *uio_dma_map(int fd, struct uio_dma_area *area,
+ unsigned int devid, unsigned int dir)
+{
+ struct uio_dma_mapping *m;
+ struct {
+ struct uio_dma_map_req req;
+ uint64_t dmaddr[area->chunk_count];
+ } mreq;
+
+ int err, i;
+
+ m = malloc(sizeof(*m) + sizeof(uint64_t) * area->chunk_count);
+ if (!m)
+ return NULL;
+
+ mreq.req.mmap_offset = area->mmap_offset;
+ mreq.req.devid = devid;
+ mreq.req.direction = dir;
+ mreq.req.chunk_count = area->chunk_count;
+ mreq.req.flags = 0;
+ for (i=0; i < area->chunk_count; i++)
+ mreq.dmaddr[i] = 0;
+
+ err = ioctl(fd, UIO_DMA_MAP, (unsigned long) &mreq);
+ if (err)
+ goto failed;
+
+ m->devid = devid;
+ m->direction = dir;
+ m->size = area->size;
+ m->chunk_count = area->chunk_count;
+ m->chunk_shift = ulog2(area->chunk_size);
+ m->mmap_offset = area->mmap_offset;
+ m->addr = area->addr;
+ for (i=0; i < m->chunk_count; i++)
+ m->dmaddr[i] = mreq.dmaddr[i];
+
+ return m;
+
+failed:
+ err = errno;
+ free(m);
+ errno = err;
+ return NULL;
+}
+
+int uio_dma_unmap(int fd, struct uio_dma_mapping *m)
+{
+ struct uio_dma_unmap_req ureq;
+
+ ureq.mmap_offset = m->mmap_offset;
+ ureq.devid = m->devid;
+ ureq.direction = m->direction;
+ ureq.flags = 0;
+ if (ioctl(fd, UIO_DMA_UNMAP, (unsigned long) &ureq) < 0)
+ return -1;
+ free(m);
+ return 0;
+}
--
1.7.1
More information about the gPXE-devel
mailing list