Imported as-is from the UIO-DMA repository. Signed-off-by: Piotr Jaroszyński <[email protected]> --- 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 <[email protected]> + + 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 <[email protected]> + + 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 <[email protected]> + + 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 _______________________________________________ gPXE-devel mailing list [email protected] http://etherboot.org/mailman/listinfo/gpxe-devel
