[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