author | Murali Karicheri <m-karicheri2@ti.com> | |
Thu, 29 Jan 2015 19:05:11 +0000 (14:05 -0500) | ||
committer | Murali Karicheri <m-karicheri2@ti.com> | |
Thu, 29 Jan 2015 19:05:11 +0000 (14:05 -0500) |
Following commits from original arago repo at
git://arago-project.org/git/projects/mcsdk-apps.git
Following commits are captured from the original repo.
ecd1f0a41871bb91a7d806e6baa228290ade543e udma: udma test waits for all expected tx/rx completes
c3c7f6dbf421179e5d44b194ad2c9754b35bd11d udma: corrects buffer length in strncpy for null termination
18de2f6f7b34c2e33fa8c7f596af7a6da4431127 udma: replace sprintf by snprintf
dbdda03f4d1d439842b07afff05109217cdac325 udma: Update udma test code to modify as per syslib tests
c3b0945a8299150f5609a78020c5962421b1bcc7 udma: Fixed syntax errors with cplusplus builds
4bbbb06ae8250df273918148eaa7dd6417880ee6 udma: Update test code to increase num_packets
ff057ae96bfede47330edd1bf13a50948586e4d7 udma: Update extern C if cplusplus definition
7433c5b3473f5d93c1d4089c36f0615b9179541c udma: Calling udma_chan_poll with 1 packet at a time
eb48b1debe76453234b46632e4afb4100d1eef23 udma: udma test code changes
f8fe455232799a0428d7b38101953bfd2ca14b1b udma: Making changes to use the select functionality available in kernel now
a529d4a2a4d4689c06e154a39dd5f1a556f1ce71 udma: Made changes to makefile for arago build to work
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
git://arago-project.org/git/projects/mcsdk-apps.git
Following commits are captured from the original repo.
ecd1f0a41871bb91a7d806e6baa228290ade543e udma: udma test waits for all expected tx/rx completes
c3c7f6dbf421179e5d44b194ad2c9754b35bd11d udma: corrects buffer length in strncpy for null termination
18de2f6f7b34c2e33fa8c7f596af7a6da4431127 udma: replace sprintf by snprintf
dbdda03f4d1d439842b07afff05109217cdac325 udma: Update udma test code to modify as per syslib tests
c3b0945a8299150f5609a78020c5962421b1bcc7 udma: Fixed syntax errors with cplusplus builds
4bbbb06ae8250df273918148eaa7dd6417880ee6 udma: Update test code to increase num_packets
ff057ae96bfede47330edd1bf13a50948586e4d7 udma: Update extern C if cplusplus definition
7433c5b3473f5d93c1d4089c36f0615b9179541c udma: Calling udma_chan_poll with 1 packet at a time
eb48b1debe76453234b46632e4afb4100d1eef23 udma: udma test code changes
f8fe455232799a0428d7b38101953bfd2ca14b1b udma: Making changes to use the select functionality available in kernel now
a529d4a2a4d4689c06e154a39dd5f1a556f1ce71 udma: Made changes to makefile for arago build to work
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
13 files changed:
Makefile | [new file with mode: 0755] | patch | blob |
include/udma.h | [new file with mode: 0644] | patch | blob |
include/udma_chan.h | [new file with mode: 0755] | patch | blob |
include/udma_mem.h | [new file with mode: 0644] | patch | blob |
internal/linux_udma.h | [new file with mode: 0644] | patch | blob |
internal/linux_vring.h | [new file with mode: 0644] | patch | blob |
internal/udma_atom.h | [new file with mode: 0644] | patch | blob |
internal/udma_atom_arm.h | [new file with mode: 0644] | patch | blob |
internal/udma_internal.h | [new file with mode: 0755] | patch | blob |
udma.c | [new file with mode: 0644] | patch | blob |
udma_chan.c | [new file with mode: 0755] | patch | blob |
udma_mem.c | [new file with mode: 0644] | patch | blob |
udma_test.c | [new file with mode: 0755] | patch | blob |
diff --git a/Makefile b/Makefile
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,43 @@
+ARCH?=arm
+CROSS_COMPILE?=arm-none-linux-gnueabi-
+
+CC?=$(CROSS_COMPILE)gcc
+AR?=$(CROSS_COMPILE)ar
+
+ARFLAGS?=crus
+LDFLAGS?= -lpthread -Wl,--hash-style=gnu
+CFLAGS?= \
+ -march=armv7-a -mtune=cortex-a8 \
+ -mthumb-interwork -mno-thumb
+
+EXTRA_CFLAGS= \
+ -Os -Iinclude -I. \
+ -D_GNU_SOURCE -DARCH_$(ARCH)
+
+UDMA_LIB_OBJS=udma.o udma_mem.o udma_chan.o
+UDMA_LIB=libudma
+
+UDMA_TEST_OBJS=udma_test.o
+UDMA_TEST=udma_test
+
+all: $(UDMA_LIB).so $(UDMA_LIB).a $(UDMA_TEST)
+
+.PHONY: all build clean distclean
+
+$(UDMA_TEST): $(UDMA_TEST_OBJS) $(UDMA_LIB).a
+ $(CC) -g -ggdb2 ${LDFLAGS} -o $@ $^ ./$(UDMA_LIB).a
+
+$(UDMA_LIB).so: $(UDMA_LIB_OBJS)
+ $(CC) -g -ggdb2 -Wl,-soname=$@.1 -shared -fPIC ${LDFLAGS} -o $@ $^
+
+$(UDMA_LIB).a: $(UDMA_LIB_OBJS)
+ $(AR) ${ARFLAGS} $@ $^
+
+%.o: %.c
+ $(CC) -g -ggdb2 ${CFLAGS} ${EXTRA_CFLAGS} -c -o $@ $<
+
+clean:
+ rm -rf $(UDMA_LIB).so $(UDMA_LIB).a $(UDMA_TEST) *.o
+
+distclean: clean
+
diff --git a/include/udma.h b/include/udma.h
--- /dev/null
+++ b/include/udma.h
@@ -0,0 +1,73 @@
+/*
+ * udma.h
+ *
+ * This file provides functionality to user space applications to use the udma
+ * kernel driver.
+ *
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 __UDMA__H__
+#define __UDMA__H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <udma_mem.h>
+#include <udma_chan.h>
+
+enum udma_dbg_level {
+ udma_dbg_verbose,
+ udma_dbg_debug,
+ udma_dbg_info,
+ udma_dbg_warning,
+ udma_dbg_error,
+};
+
+struct udma_osal {
+ void (*lock)(void);
+ void (*unlock)(void);
+ void *(*malloc)(unsigned size);
+ void (*free)(void *data);
+};
+
+int udma_init(struct udma_osal *osal);
+void udma_shutdown(void);
+void udma_set_dbg_level(enum udma_dbg_level level);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __UDMA__H__ */
diff --git a/include/udma_chan.h b/include/udma_chan.h
--- /dev/null
+++ b/include/udma_chan.h
@@ -0,0 +1,72 @@
+/*
+ * udma_chan.h
+ * This file provides udma channel functionality to user space applications
+ * to use the udma kernel driver.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 __UDMA_CHAN__H__
+#define __UDMA_CHAN__H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+
+struct udma_chan;
+
+enum udma_chan_dir {
+ UDMA_CHAN_TX,
+ UDMA_CHAN_RX
+};
+
+typedef void (*udma_chan_callback_t)(struct udma_chan *chan, void *handle,
+ void *buf, unsigned size);
+
+struct udma_chan *udma_chan_create(const char *name, enum udma_chan_dir dir,
+ int num_desc);
+void udma_chan_destroy(struct udma_chan *chan);
+int udma_chan_submit(struct udma_chan *chan, void *handle,
+ udma_chan_callback_t cb,
+ void *buf, unsigned size);
+void udma_chan_poll(struct udma_chan *chan, int budget,
+ struct timespec *timeout);
+void udma_chan_kick(struct udma_chan *chan);
+int udma_chan_get_fd(struct udma_chan *chan);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __UDMA_CHAN__H__ */
diff --git a/include/udma_mem.h b/include/udma_mem.h
--- /dev/null
+++ b/include/udma_mem.h
@@ -0,0 +1,73 @@
+/*
+ * udma_mem.h
+ *
+ * UDMA Memory management provides the ability to manage pre-allocated
+ * fixed-size pools of buffers through its segment/partition construct.
+ *
+ * Partitions are then created out of a UDMA segment, with each partition
+ * consisting of a number of fixed-size blocks that can be allocated
+ * from and returned to the partition with very little overhead.
+ *
+ * This memory manager implementation relies on an atomic LIFO construct to
+ * manage partitions without resorting to system calls or expensive heap
+ * operations.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 __UDMA_MEM__H__
+#define __UDMA_MEM__H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct udma_mem_part;
+
+int udma_mem_init(unsigned long mem_size);
+void udma_mem_shutdown(void);
+
+void *udma_mem_alloc(unsigned long size);
+int udma_mem_free(void *mem, unsigned long size);
+
+struct udma_mem_part *
+udma_mem_part_create(unsigned nblocks, unsigned blocksize);
+void udma_mem_part_destroy(struct udma_mem_part *part);
+
+void *udma_mem_block_alloc(struct udma_mem_part *part);
+void udma_mem_block_free(struct udma_mem_part *part, void* block);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __UDMA_MEM__H__ */
diff --git a/internal/linux_udma.h b/internal/linux_udma.h
--- /dev/null
+++ b/internal/linux_udma.h
@@ -0,0 +1,68 @@
+ /*
+ * linux_udma.h
+ * This file shares some data structures with the linux kernel header file
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 _LINUX_UDMA_H
+#define _LINUX_UDMA_H
+
+#include <linux/types.h>
+
+enum dma_transfer_direction {
+ DMA_MEM_TO_MEM,
+ DMA_MEM_TO_DEV,
+ DMA_DEV_TO_MEM,
+ DMA_DEV_TO_DEV,
+ DMA_TRANS_NONE,
+};
+
+struct udma_chan_data {
+ unsigned long ring_virt; /* in */
+ unsigned ring_size; /* in */
+ unsigned num_desc; /* in */
+ unsigned align; /* in */
+ char name[64]; /* in */
+ int eventfd; /* in */
+ enum dma_transfer_direction direction; /* in */
+
+ int handle; /* out */
+};
+
+#define UDMA_IOC_MAGIC 'I'
+#define UDMA_IOC_ATTACH _IOWR(UDMA_IOC_MAGIC, 0, struct udma_chan_data)
+#define UDMA_IOC_DETACH _IOW (UDMA_IOC_MAGIC, 1, int)
+#define UDMA_IOC_KICK _IOW (UDMA_IOC_MAGIC, 2, int)
+
+#endif /* _LINUX_UDMA_H */
diff --git a/internal/linux_vring.h b/internal/linux_vring.h
--- /dev/null
+++ b/internal/linux_vring.h
@@ -0,0 +1,187 @@
+/* An interface for efficient virtio implementation.
+ *
+ * This header is BSD licensed so anyone can use the definitions
+ * to implement compatible drivers/servers.
+ *
+ * Copyright 2007, 2009, IBM Corporation
+ * Copyright 2011, Red Hat, Inc
+ * All rights reserved.
+ *
+ * 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 IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 IBM OR 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.
+ */
+ /* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 VIRTIO_RING_H
+#define VIRTIO_RING_H
+
+/* This marks a buffer as continuing via the next field. */
+#define VRING_DESC_F_NEXT 1
+
+/* This marks a buffer as write-only (otherwise read-only). */
+#define VRING_DESC_F_WRITE 2
+
+/*
+ * The Host uses this in used->flags to advise the Guest: don't kick me
+ * when you add a buffer. It's unreliable, so it's simply an
+ * optimization. Guest will still kick if it's out of buffers.
+ */
+#define VRING_USED_F_NO_NOTIFY 1
+
+/*
+ * The Guest uses this in avail->flags to advise the Host: don't
+ * interrupt me when you consume a buffer. It's unreliable, so it's
+ * simply an optimization.
+ */
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+/*
+ * Virtio ring descriptors: 16 bytes.
+ * These can chain together via "next".
+ */
+
+struct vring_desc {
+ uint64_t addr; /* Address (guest-physical). */
+ uint32_t len; /* Length. */
+ uint16_t flags; /* The flags as indicated above. */
+ uint16_t next; /* We chain unused descriptors via this, too */
+};
+
+struct vring_avail {
+ uint16_t flags;
+ uint16_t idx;
+ uint16_t ring[];
+ /* uint16_t used_event; */
+};
+#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
+
+/* u32 is used here for ids for padding reasons. */
+
+struct vring_used_elem {
+ uint32_t id; /* Index of start of used descriptor chain. */
+ uint32_t len; /* Total length of the descriptor chain which was
+ written to. */
+};
+
+struct vring_used {
+ uint16_t flags;
+ uint16_t idx;
+ struct vring_used_elem ring[];
+ /* uint16_t avail_event; */
+};
+#define vring_avail_event(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])
+
+struct vring {
+ unsigned int num;
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
+};
+
+/* The standard layout for the ring is a continuous chunk of memory which
+ * looks like this. We assume num is a power of 2.
+ *
+ * struct vring {
+ * // The actual descriptors (16 bytes each)
+ * struct vring_desc desc[num];
+ *
+ * // A ring of available descriptor heads with free-running index.
+ * __u16 avail_flags;
+ * __u16 avail_idx;
+ * __u16 available[num];
+ *
+ * // Padding to the next align boundary.
+ * char pad[];
+ *
+ * // A ring of used descriptor heads with free-running index.
+ * __u16 used_flags;
+ * __u16 EVENT_IDX;
+ * struct vring_used_elem used[num];
+ * };
+ * Note: for virtio PCI, align is 4096.
+ */
+
+static inline void vring_init(struct vring *vr, unsigned int num,
+ void *p, unsigned long align)
+{
+ vr->num = num;
+ vr->desc = p;
+ vr->avail = p + num*sizeof(struct vring_desc);
+ vr->used = (void *)(((unsigned long)&vr->avail->ring[num]
+ + align-1) & ~(align - 1));
+}
+
+static inline unsigned vring_size(unsigned int num, unsigned long align)
+{
+ unsigned ret;
+
+ ret = sizeof(struct vring_desc) * num;
+ ret += sizeof(uint16_t) * (2 + num);
+
+ ret = (ret + align - 1) & ~(align - 1);
+ ret += sizeof(uint16_t) * 3;
+ ret += sizeof(struct vring_used_elem) * num;
+
+ return ret;
+}
+
+static inline int vring_need_event(uint16_t event_idx,
+ uint16_t new_idx, uint16_t old_idx)
+{
+ return ((uint16_t)(new_idx - event_idx - 1) <
+ (uint16_t)(new_idx - old_idx));
+}
+
+#endif /* VIRTIO_RING_H */
diff --git a/internal/udma_atom.h b/internal/udma_atom.h
--- /dev/null
+++ b/internal/udma_atom.h
@@ -0,0 +1,392 @@
+/*
+ * udma_atom.h
+ *
+ * UDMA uses processor specific atomic primitives to avoid system
+ * calls and locks in many situations.
+ *
+ * For instance, LIFO list primitives built upon atomic compare-and-set
+ * operations serve as the primary data structure used in the memory
+ * management facility.
+ *
+ * This file contains architecture independent primitives (such as
+ * the above mentioned LIFO list) that rely on an architecture dependent
+ * implementation of compare-and-set. These architecture specific
+ * implementations can be found in arch/ARCH/udma_atom_arch.h.
+ *
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 __UDMA_ATOM__H__
+#define __UDMA_ATOM__H__
+
+/** An atomic object structure */
+struct udma_atom
+{
+ volatile int counter; /**< The actual value */
+};
+
+/** A lock-free LIFO list type */
+struct udma_lifo
+{
+ struct udma_atom head; /**< The head of the list */
+};
+
+/** A lock-free LIFO list node structure */
+struct udma_lifo_node
+{
+ struct udma_atom next; /**< the next node in the list */
+};
+
+enum udma_atom_status
+{
+ /** Compare-and-set operation succeeded, the atomic object has been
+ * modified */
+ UDMA_ATOM_CAS_SUCCESS = 0,
+
+ /** Compare-and-set operation failed because of interruption, the
+ * operation should be retried */
+ UDMA_ATOM_CAS_RETRY,
+
+ /** Compare-and-set operation failed because the object did not match
+ * the compare value */
+ UDMA_ATOM_CAS_FAILED
+};
+
+#if defined(ARCH_arm)
+#include <internal/udma_atom_arm.h>
+#else
+#error "unknown arch"
+#endif
+
+/**
+ * @brief Static initializer for an atomic object with a default value of "x"
+ */
+#define UDMA_ATOM_INIT(x) { (int)(x) }
+
+/**
+ * @brief Static initializer for an empty atomic
+ * LIFO list.
+ */
+#define UDMA_LIFO_INIT { UDMA_ATOM_INIT(NULL) }
+
+/**
+ * @brief Get the integer value of an atomic object.
+ * @param[in] object Atomic object whose value is to be fetched.
+ * @return Retreived value of the object.
+ */
+static inline int udma_atom_get(struct udma_atom *object)
+{
+ return object->counter;
+}
+
+/**
+ * @brief Get the pointer value of an atomic object.
+ * @param[in] object Atomic object whose value is to be fetched.
+ * @return Retreived value of the object.
+ */
+static inline void *udma_atom_get_ptr(struct udma_atom *object)
+{
+ return (void*)udma_atom_get(object);
+}
+
+/**
+ * @brief Set an atomic object to a specified integer value
+ * @param[in] object Pointer to the atomic object to be set.
+ * @param[in] value Value to set the object to.
+ * @return none
+ * @see udma_atom_cas
+ *
+ * <B>Detailed Description:</B>
+ *
+ * This routine unconditionally sets an atomic object to a specified value. To
+ * conditionally set the object, use udma_atom_cas() instead.
+ */
+static inline void udma_atom_set(struct udma_atom *object, int value)
+{
+ object->counter = value;
+}
+
+/**
+ * @brief Set an atomic object to a specified pointer value
+ * @param[in] object Pointer to the atomic object to be set.
+ * @param[in] value Value to set the object to.
+ * @return none
+ * @see udma_atom_cas
+ *
+ * <B>Detailed Description:</B>
+ *
+ * This routine unconditionally sets an atomic object to a specified value. To
+ * conditionally set the object, use udma_atom_cas() instead.
+ */
+static inline void udma_atom_set_ptr(struct udma_atom *object, void *value)
+{
+ udma_atom_set(object, (int)value);
+}
+
+/**
+ * @brief Wrapper around udma_atom_cas for pointer data.
+ * @param[in] v Atomic object on which to operate.
+ * @param[in] cmp Value to compare object against.
+ * @param[in] val Value to set object to if comparison
+ * holds true.
+ *
+ * @return UDMA_ATOM_CAS_FAILED CAS operation failed because
+ * object value did not match
+ * the compare value.
+ *
+ * @return UDMA_ATOM_CAS_RETRY CAS operation failed because
+ * the operation was interrupted,
+ * but may succeed if retried.
+ *
+ * @return UDMA_ATOM_CAS_SUCCESS CAS operation succeeded, the
+ * object has been modified.
+ *
+ * <B>Detailed Description:</B>
+ *
+ * This routine provides a simple wrapper around udma_atom_cas for
+ * pointer typed data.
+ */
+static inline enum udma_atom_status
+udma_atom_cas_ptr(struct udma_atom *v, void *cmp, void *val)
+{
+ return udma_atom_cas(v, (int)cmp, (int)val);
+}
+
+/**
+ * @brief Dynamic initializer for an atomic object.
+ * @param[in] object Atomic object to be initialized.
+ * @param[in] defval Default value.
+ * @return none
+ */
+static inline void udma_atom_init(struct udma_atom *object, int defval)
+{
+ udma_atom_set(object, defval);
+}
+
+/**
+ * @brief Dynamic initializer for an atomic object.
+ * @param[in] object Atomic object to be initialized.
+ * @param[in] defval Default value.
+ * @return none
+ */
+static inline void udma_atom_init_ptr(struct udma_atom *object, void *defval)
+{
+ udma_atom_set_ptr(object, defval);
+}
+
+/**
+ * @brief Atomically set an object and return the original value.
+ * @param[in] object Atomic object to be modified.
+ * @param[in] value Value to set object to
+ * @return The original value.
+ */
+static inline int udma_atom_xchg(struct udma_atom *object, int newval)
+{
+ enum udma_atom_status status;
+ int oldval;
+
+ do {
+ oldval = udma_atom_get(object);
+ status = udma_atom_cas(object, oldval, newval);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+
+ return oldval;
+}
+
+/**
+ * @brief Atomically set an object pointer and return the original value.
+ * @param[in] object Atomic object to be modified.
+ * @param[in] value Value to set object to
+ * @return The original value.
+ */
+static inline void *udma_atom_xchg_ptr(struct udma_atom *object, void *newval)
+{
+ enum udma_atom_status status;
+ void *oldval;
+
+ do {
+ oldval = udma_atom_get_ptr(object);
+ status = udma_atom_cas_ptr(object, oldval, newval);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+
+ return oldval;
+}
+
+/**
+ * @brief Atomically set a bit in an object and return the original
+ * bit value.
+ * @param[in] object Atomic object to be modified.
+ * @param[in] bit Bit number (0 <= i < 32).
+ * @return The original bit.
+ */
+static inline int udma_atom_set_bit(struct udma_atom *object, int bit)
+{
+ enum udma_atom_status status;
+ int mask = (1 << bit);
+ int oldval, newval;
+
+ do {
+ oldval = udma_atom_get(object);
+ if (oldval & mask)
+ return 1;
+ newval = oldval | mask;
+ status = udma_atom_cas(object, oldval, newval);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+ return 0;
+}
+
+/**
+ * @brief Atomically clear a bit in an object and return the original
+ * bit value.
+ * @param[in] object Atomic object to be modified.
+ * @param[in] bit Bit number (0 <= i < 32).
+ * @return The original bit.
+ */
+static inline int udma_atom_clear_bit(struct udma_atom *object, int bit)
+{
+ enum udma_atom_status status;
+ int mask = (1 << bit);
+ int oldval, newval;
+
+ do {
+ oldval = udma_atom_get(object);
+ if (!(oldval & mask))
+ return 0;
+ newval = oldval & (~mask);
+ status = udma_atom_cas(object, oldval, newval);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+ return 1;
+}
+
+/**
+ * @brief Atomically add a constant value to the contents of an
+ * atomic object.
+ * @param[in] object Atomic object to be modified.
+ * @param[in] i Increment value.
+ * @return The modified result.
+ */
+static inline int udma_atom_add(struct udma_atom *object, int i)
+{
+ enum udma_atom_status status;
+ int oldval, newval;
+ do {
+ oldval = udma_atom_get(object);
+ newval = oldval + i;
+ status = udma_atom_cas(object, oldval, newval);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+ return newval;
+}
+
+/**
+ * @brief Atomically subtract a constant value to the
+ * contents of an atomic object.
+ * @param[in] object Atomic object to be modified.
+ * @param[in] i Decrement value.
+ * @return The modified result.
+ */
+static inline int udma_atom_sub(struct udma_atom *object, int i)
+{
+ return udma_atom_add(object, -i);
+}
+
+/**
+ * @brief Atomically increment an atomic object.
+ * @param[in] object Atomic object to be modified.
+ * @return The modified result.
+ */
+static inline int udma_atom_inc(struct udma_atom *object)
+{
+ return udma_atom_add(object, 1);
+}
+
+/**
+ * @brief Atomically decrement an atomic object.
+ * @param[in] object Atomic object to be modified.
+ * @return The modified result.
+ */
+static inline int udma_atom_dec(struct udma_atom *object)
+{
+ return udma_atom_sub(object, 1);
+}
+
+/**
+ * @brief Dynamic initializer for an lock-free LIFO list.
+ * @param[in] lifo List object to be initialized.
+ * @return none
+ */
+static inline void udma_lifo_init(struct udma_lifo *lifo)
+{
+ udma_atom_set_ptr(&lifo->head, NULL);
+}
+
+/**
+ * @brief Insert a new node at the head of the LIFO list.
+ * @param[in] lifo List object to be manipulated.
+ * @param[in] node New node to be inserted.
+ * @return none
+ */
+static inline void udma_lifo_put(struct udma_lifo *lifo,
+ struct udma_lifo_node *node)
+{
+ enum udma_atom_status status;
+ struct udma_lifo_node *head;
+
+ do {
+ head = udma_atom_get_ptr(&lifo->head);
+ udma_atom_set_ptr(&node->next, head);
+ status = udma_atom_cas_ptr(&lifo->head, head, node);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+}
+
+/**
+ * @brief Delete and return the head node of a LIFO list.
+ * @param[in] lifo List object to be manipulated.
+ * @return node Extracted node.
+ */
+static inline struct udma_lifo_node *udma_lifo_get(struct udma_lifo *lifo)
+{
+ enum udma_atom_status status;
+ struct udma_lifo_node * head, * next;
+
+ do {
+ head = udma_atom_get_ptr(&lifo->head);
+ if (!head)
+ break;
+ next = udma_atom_get_ptr(&head->next);
+ status = udma_atom_cas_ptr(&lifo->head, head, next);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+ return head;
+}
+
+#endif /* __UDMA_ATOM__H__ */
diff --git a/internal/udma_atom_arm.h b/internal/udma_atom_arm.h
--- /dev/null
+++ b/internal/udma_atom_arm.h
@@ -0,0 +1,87 @@
+/*
+ * udma.h
+ *
+ * Architecture specific (ARM9) routines for atomic operations
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 __UDMA_ATOM_ARCH_ARM__
+#define __UDMA_ATOM_ARCH_ARM__
+
+#define LINUX_USER_HELPER_CMPXCHG 0xffff0fc0
+
+/*
+ * @brief Kernel user mode cmpxchg helper routine type.
+ * See arch/arm/kernel/entry-armv.S in the kernel
+ * source for further details.
+ */
+typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
+
+#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)(LINUX_USER_HELPER_CMPXCHG))
+
+/**
+ * @brief Perform an atomic compare-and-set operation
+ *
+ * @param[in] v Atomic object on which to operate.
+ * @param[in] cmp Value to compare object against.
+ * @param[in] val Value to set object to if comparison
+ * holds true.
+ *
+ * @return UDMA_ATOM_CAS_FAILED CAS operation failed because
+ * object value did not match
+ * the compare value.
+ *
+ * @return UDMA_ATOM_CAS_SUCCESS CAS operation succeeded, the
+ * object has been modified.
+ *
+ * <B>Detailed Description:</B>
+ *
+ * This routine implements a compare-and-set atomic primitive
+ * using processor specific and linux specific constructs.
+ *
+ * In the case of ARM9, since ldrex/strex instructions are
+ * not present in most common pre-ARMV processors, the kernel
+ * provides user-mode helper routines at a predefined address.
+ * These user-mode routines were provided primarily for NPTL
+ * use, but works out quite conveniently for our purposes as
+ * well.
+ */
+static inline enum udma_atom_status
+udma_atom_cas(struct udma_atom *v, int cmp, int val)
+{
+ return __kernel_cmpxchg(cmp, val, &v->counter) ?
+ UDMA_ATOM_CAS_FAILED : UDMA_ATOM_CAS_SUCCESS;
+}
+
+#endif /* __UDMA_ATOM_ARCH_ARM__ */
diff --git a/internal/udma_internal.h b/internal/udma_internal.h
--- /dev/null
+++ b/internal/udma_internal.h
@@ -0,0 +1,125 @@
+/*
+ * udma.h
+ *
+ * This file provides internal functionality to user space applications
+ * to use the udma kernel driver.
+ *
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 __UDMA_INTERNAL__H__
+#define __UDMA_INTERNAL__H__
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/eventfd.h>
+#include <sys/mman.h>
+
+#include <udma.h>
+
+#include <internal/linux_udma.h>
+#include <internal/linux_vring.h>
+#include <internal/udma_atom.h>
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#define UDMA_DEV_NAME "/dev/udma0"
+#define UDMA_DBG_DEV_NAME "/dev/kmsg"
+
+extern int udma_fd;
+extern FILE *udma_dbg_fd;
+extern enum udma_dbg_level udma_dbg_level;
+extern struct udma_osal *udma_osal;
+
+#define __udma_print(level, ...) \
+ do { \
+ if ((level) >= udma_dbg_level) { \
+ fprintf(udma_dbg_fd, __VA_ARGS__); \
+ fflush(udma_dbg_fd); \
+ } \
+ } while (0)
+
+#define udma_print_verbose(...) __udma_print(udma_dbg_verbose, __VA_ARGS__)
+#define udma_print_debug(...) __udma_print(udma_dbg_debug, __VA_ARGS__)
+#define udma_print_info(...) __udma_print(udma_dbg_info, __VA_ARGS__)
+#define udma_print_warning(...) __udma_print(udma_dbg_warning, __VA_ARGS__)
+#define udma_print_error(...) __udma_print(udma_dbg_error, __VA_ARGS__)
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+static inline void udma_lock(void)
+{
+ if (udma_osal && udma_osal->lock)
+ (*udma_osal->lock)();
+}
+
+static inline void udma_unlock(void)
+{
+ if (udma_osal && udma_osal->unlock)
+ (*udma_osal->unlock)();
+}
+
+static inline void *udma_malloc(unsigned size)
+{
+ if (udma_osal && udma_osal->malloc)
+ return (*udma_osal->malloc)(size);
+ else
+ return malloc(size);
+}
+
+static inline void udma_free(void *data)
+{
+ if (udma_osal && udma_osal->free)
+ (*udma_osal->free)(data);
+ else
+ free(data);
+}
+
+struct udma_mem_part {
+ unsigned blocksize;
+ void *memstart, *memend;
+ struct udma_atom used;
+ struct udma_lifo free;
+};
+
+#endif
diff --git a/udma.c b/udma.c
--- /dev/null
+++ b/udma.c
@@ -0,0 +1,72 @@
+/*
+ * udma.c
+ *
+ * This file provides functionality to user space applications to use the udma
+ * kernel driver.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ *
+*/
+
+#include <internal/udma_internal.h>
+
+int udma_fd = -1;
+FILE *udma_dbg_fd = NULL;
+struct udma_osal *udma_osal = NULL;
+enum udma_dbg_level udma_dbg_level = udma_dbg_info;
+
+void udma_set_dbg_level(enum udma_dbg_level level)
+{
+ udma_dbg_level = level;
+}
+
+int udma_init(struct udma_osal *osal)
+{
+ udma_osal = osal;
+
+ udma_fd = open(UDMA_DEV_NAME, O_RDWR);
+ if (udma_fd < 0)
+ return -errno;
+
+ udma_dbg_fd = fopen(UDMA_DBG_DEV_NAME, "w");
+ if (!udma_dbg_fd)
+ udma_dbg_fd = stderr;
+
+ return 0;
+}
+
+void udma_shutdown(void)
+{
+ close(udma_fd);
+ udma_fd = -1;
+}
+
diff --git a/udma_chan.c b/udma_chan.c
--- /dev/null
+++ b/udma_chan.c
@@ -0,0 +1,343 @@
+/*
+ * udma_chan.c
+ * This file provides udma channel functionality to user space applications
+ * to use the udma kernel driver.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ *
+*/
+
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#include <internal/udma_internal.h>
+
+static int udma_align = 64;
+
+struct udma_chan {
+ void *mem;
+ unsigned size, num_desc;
+ struct udma_chan_data data;
+ struct vring vring;
+ struct udma_desc_data *desc_data;
+
+ struct udma_atom last_used_idx;
+ struct udma_atom num_free;
+ struct udma_atom free_head;
+};
+
+struct udma_desc_data {
+ void *handle;
+ udma_chan_callback_t cb;
+ void *buf;
+ unsigned size;
+};
+
+int udma_chan_get_size(int num_desc)
+{
+ return (sizeof(struct udma_chan) +
+ sizeof(struct udma_desc_data) * num_desc);
+}
+
+struct udma_chan *udma_chan_create(const char *name, enum udma_chan_dir dir,
+ int num_desc)
+{
+ struct udma_chan_data *data;
+ struct udma_chan *chan;
+ struct vring *vring;
+ unsigned size;
+ void *mem;
+ int ret, i;
+
+ /* descriptors must be a power of two */
+ if (num_desc & (num_desc - 1)) {
+ fprintf(stderr, "number of descriptors not a power of two\n");
+ return NULL;
+ }
+
+ chan = udma_malloc(udma_chan_get_size(num_desc));
+ if (!chan) {
+ fprintf(stderr, "failed to allocate channel\n");
+ return NULL;
+ }
+
+ if (dir != UDMA_CHAN_TX && dir != UDMA_CHAN_RX) {
+ fprintf(stderr, "bad channel direction\n");
+ return NULL;
+ }
+ udma_lock();
+
+ memset(chan, 0, udma_chan_get_size(num_desc));
+
+ chan->desc_data = (struct udma_desc_data*)(chan + 1);
+ chan->num_desc = num_desc;
+
+ size = vring_size(num_desc, udma_align);
+ mem = udma_mem_alloc(size);
+ if (!mem) {
+ udma_free(chan);
+ udma_unlock();
+ fprintf(stderr, "failed to allocate mem\n");
+ return NULL;
+ }
+
+ vring = &chan->vring;
+ data = &chan->data;
+
+ data->num_desc = num_desc;
+ data->align = udma_align;
+ data->ring_virt = (unsigned long)mem;
+ data->ring_size = size;
+ data->direction = (dir == UDMA_CHAN_TX) ? DMA_MEM_TO_DEV :
+ DMA_DEV_TO_MEM;
+ udma_atom_set(&chan->num_free, num_desc);
+ udma_atom_set(&chan->free_head, 0);
+ strncpy(data->name, name, sizeof(data->name) - 1);
+
+ vring_init(&chan->vring, num_desc, mem, udma_align);
+
+ ret = ioctl(udma_fd, UDMA_IOC_ATTACH, data);
+ if (ret < 0) {
+ udma_mem_free(mem, size);
+ udma_free(chan);
+ udma_unlock();
+ fprintf(stderr, "failed to attach\n");
+ return NULL;
+ }
+
+ for (i = 0; i < num_desc; i++)
+ vring->desc[i].next = i + 1;
+
+ chan->mem = mem;
+ chan->size = size;
+
+ udma_unlock();
+
+ return chan;
+}
+
+void udma_chan_destroy(struct udma_chan *chan)
+{
+ close(chan->data.handle);
+ udma_mem_free(chan->mem, chan->size);
+ udma_free(chan);
+}
+
+int udma_chan_get_fd(struct udma_chan *chan)
+{
+ return(chan->data.handle);
+}
+
+void udma_chan_kick(struct udma_chan *chan)
+{
+ struct vring *vring = &chan->vring;
+ struct timespec timeo = {0, 0};
+ fd_set rfds, wrfds, efds;
+ int retval;
+
+ udma_print_debug("kick (%s) begin - avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+
+ FD_ZERO(&rfds);
+ FD_SET(chan->data.handle, &rfds);
+ FD_ZERO(&wrfds);
+ FD_SET(chan->data.handle, &wrfds);
+ FD_ZERO(&efds);
+ FD_SET(chan->data.handle, &efds);
+
+ retval = pselect(chan->data.handle + 1, &rfds,
+ &wrfds, &efds, &timeo, NULL);
+ if (retval == -1)
+ udma_print_error("kick (%s) select failed ret= %d\n",
+ chan->data.name, retval);
+ else if (retval)
+ udma_print_debug("kick (%s) end - avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+ else
+ udma_print_debug("kick (%s) no data after timeout, ret"
+ "= %d\n", chan->data.name, retval);
+
+}
+
+void udma_chan_poll(struct udma_chan *chan, int budget, struct timespec *timeo)
+{
+ struct vring *vring = &chan->vring;
+ enum udma_atom_status status;
+ struct udma_desc_data *data;
+ int id, head, retval;
+ uint32_t size;
+ unsigned short idx;
+ void *handle, *buf;
+ fd_set rfds, wrfds, efds;
+
+ udma_print_debug("poll (%s) begin - avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+
+ /* Right now, nothing to read, just poll
+ ret = read(chan->data.handle, &packets, sizeof(int));
+ udma_print_debug("first read, packets = %d\n", packets);
+ udma_print_debug("poll (%s) avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+ */
+ for (;;) {
+ if (unlikely(budget == 0))
+ break;
+
+ idx = udma_atom_get(&chan->last_used_idx);
+ udma_print_debug("poll (%s) idx %d\n",
+ chan->data.name, idx);
+
+ /* do we have stuff to do in user-space? */
+ if (unlikely(idx == vring->used->idx)) {
+ FD_ZERO(&rfds);
+ FD_SET(chan->data.handle, &rfds);
+ FD_ZERO(&wrfds);
+ FD_SET(chan->data.handle, &wrfds);
+ FD_ZERO(&efds);
+ FD_SET(chan->data.handle, &efds);
+
+ retval = pselect(chan->data.handle + 1, &rfds,
+ &wrfds, &efds, timeo, NULL);
+ if (retval == -1) {
+ udma_print_error("select failed ret= %d\n",
+ retval);
+ break;
+ }
+ else if (retval)
+ udma_print_debug("data available (%s) ret = %d\n",
+ chan->data.name, retval);
+ else {
+ udma_print_debug(" no data after timeout, ret"
+ "= %d\n", retval);
+ break;
+ }
+ continue;
+ }
+
+ status = udma_atom_cas(&chan->last_used_idx, idx,
+ ((idx + 1) & 0xffff));
+
+ if (likely(status == UDMA_ATOM_CAS_SUCCESS))
+ vring_used_event(&chan->vring) = ((idx +1) & 0xffff);
+ else if (unlikely(status != UDMA_ATOM_CAS_SUCCESS))
+ continue;
+
+ udma_print_verbose("poll (%s) process %d - avail %d, used %d\n",
+ chan->data.name, idx, vring->avail->idx,
+ vring->used->idx);
+
+ idx &= chan->num_desc - 1;
+ id = vring->used->ring[idx].id;
+ size = vring->used->ring[idx].len;
+ data = chan->desc_data + id;
+ handle = data->handle;
+ buf = data->buf;
+
+ do {
+ head = udma_atom_get(&chan->free_head);
+ vring->desc[id].next = head;
+ status = udma_atom_cas(&chan->free_head, head, id);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+ udma_atom_inc(&chan->num_free);
+ barrier();
+
+ udma_print_verbose("poll (%s) pre-cb - avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+
+ (*data->cb)(chan, handle, buf, size);
+
+ if (likely(budget > 0))
+ budget--;
+
+ udma_print_verbose("poll (%s) post-cb - avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+ }
+
+ udma_print_debug("poll (%s) end - avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+}
+
+int udma_chan_submit(struct udma_chan *chan, void *handle,
+ udma_chan_callback_t cb, void *buf, unsigned size)
+{
+ struct vring *vring = &chan->vring;
+ unsigned int idx;
+ int head, next;
+ enum udma_atom_status status;
+ struct timespec timeo = { 0, 0 };
+
+ udma_print_debug("submit (%s) begin - avail %d, used %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx);
+
+ /* get desc from free list */
+ if (!udma_atom_get(&chan->num_free)) {
+ udma_chan_poll(chan, 1, &timeo);
+ }
+
+ if (udma_atom_dec(&chan->num_free) < 0) {
+ udma_atom_inc(&chan->num_free);
+ return -ENOMEM;
+ }
+
+ do {
+ head = udma_atom_get(&chan->free_head);
+ next = vring->desc[head].next;
+ status = udma_atom_cas(&chan->free_head, head, next);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+
+ /* save user's context info */
+ chan->desc_data[head].handle = handle;
+ chan->desc_data[head].cb = cb;
+ chan->desc_data[head].buf = buf;
+ chan->desc_data[head].size = size;
+ vring->desc[head].addr = (uint64_t)((uint32_t)buf);
+ vring->desc[head].len = size;
+ barrier();
+
+ /* put desc into avail list */
+ idx = vring->avail->idx;
+ vring->avail->ring[idx & (chan->num_desc - 1)] = head;
+ vring->avail->idx++;
+
+ udma_print_debug("submit (%s) end - avail %d, used %d, ring idx %d, "
+ "desc idx %d\n",
+ chan->data.name, vring->avail->idx,
+ vring->used->idx, idx, head);
+
+ return 0;
+}
diff --git a/udma_mem.c b/udma_mem.c
--- /dev/null
+++ b/udma_mem.c
@@ -0,0 +1,163 @@
+/*
+ * udma_mem.c
+ * This file provides udma memory functionality to user space applications
+ * to use the udma kernel driver.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ *
+*/
+
+#include <internal/udma_internal.h>
+
+#define align(num, align) (((num) + (align) - 1) & (~((align) - 1)))
+
+static int udma_page_size = -1;
+static void *udma_mem_start = NULL;
+static void *udma_mem_end = NULL;
+static struct udma_atom udma_mem_avail;
+
+int udma_mem_init(unsigned long mem_size)
+{
+ void *udma_mem;
+
+ udma_page_size = getpagesize();
+
+ udma_mem = mmap(0, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ udma_fd, 0);
+ if (udma_mem == MAP_FAILED)
+ return -ENOMEM;
+
+ udma_mem_start = udma_mem;
+ udma_mem_end = udma_mem + mem_size;
+ udma_atom_set_ptr(&udma_mem_avail, udma_mem_start);
+
+ return 0;
+}
+
+void udma_mem_shutdown(void)
+{
+ munmap(udma_mem_start, udma_mem_end - udma_mem_start);
+ udma_mem_start = udma_mem_end = NULL;
+ udma_atom_set_ptr(&udma_mem_avail, NULL);
+}
+
+void *udma_mem_alloc(unsigned long size)
+{
+ void *memstart, *memend;
+ enum udma_atom_status status;
+
+ size = align(size, udma_page_size);
+
+ do {
+ memstart = udma_atom_get_ptr(&udma_mem_avail);
+ memend = memstart + size;
+ if (memend > udma_mem_end)
+ return NULL;
+ status = udma_atom_cas_ptr(&udma_mem_avail, memstart, memend);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+
+ return memstart;
+}
+
+int udma_mem_free(void *mem, unsigned long size)
+{
+ void *memstart = mem, *memend, *avail;
+ enum udma_atom_status status;
+
+ size = align(size, udma_page_size);
+ memend = memstart + size;
+
+ do {
+ avail = udma_atom_get_ptr(&udma_mem_avail);
+ if (avail != memend)
+ return -EINVAL;
+ status = udma_atom_cas_ptr(&udma_mem_avail, memend, memstart);
+ } while (status != UDMA_ATOM_CAS_SUCCESS);
+
+ return 0;
+}
+
+struct udma_mem_part *udma_mem_part_create(unsigned nblocks, unsigned blocksize)
+{
+ struct udma_mem_part *part;
+ unsigned total;
+ void *mem;
+
+ part = udma_malloc(sizeof(struct udma_mem_part));
+ if (!part)
+ return NULL;
+
+ part->blocksize = align(blocksize, 4);
+ total = part->blocksize * nblocks;
+ nblocks = total / part->blocksize;
+
+ mem = udma_mem_alloc(total);
+ if (!mem) {
+ udma_free(part);
+ return NULL;
+ }
+
+ part->memstart = mem;
+ part->memend = mem + total;
+
+ udma_atom_set(&part->used, 0);
+ udma_lifo_init(&part->free);
+
+ for (; nblocks; nblocks--, mem += part->blocksize)
+ udma_lifo_put(&part->free, mem);
+
+ return part;
+}
+
+void udma_mem_part_destroy(struct udma_mem_part *part)
+{
+ udma_mem_free(part->memstart, part->memend - part->memstart);
+ udma_free(part);
+}
+
+void *udma_mem_block_alloc(struct udma_mem_part *part)
+{
+ void *block;
+
+ block = udma_lifo_get(&part->free);
+ if (block)
+ udma_atom_inc(&part->used);
+ return block;
+}
+
+void udma_mem_block_free(struct udma_mem_part *part, void* block)
+{
+ if (block < part->memstart || block >= part->memend)
+ return;
+ udma_lifo_put(&part->free, block);
+ udma_atom_dec(&part->used);
+}
diff --git a/udma_test.c b/udma_test.c
--- /dev/null
+++ b/udma_test.c
@@ -0,0 +1,240 @@
+/*
+ * udma_test.c
+ * This file provides sample udma test code to user space applications
+ * to use the udma kernel driver.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ *
+*/
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <udma.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <internal/udma_internal.h>
+
+//#define NUM_PACKETS 64
+#define NUM_PACKETS (2 * 1000 * 10 )
+#define BUF_SIZE 128
+#define NUM_DESC_PER_CHAN 16
+#define NUM_CHAN 1
+
+struct udma_user_info {
+ int buf_size;
+ int test_id;
+ int offset;
+ int num_descs;
+ int num_packets;
+ unsigned long tx_complete;
+ unsigned long rx_complete;
+};
+
+struct udma_mem_part *part = NULL;
+struct udma_chan *txchan, *rxchan;
+struct udma_chan *txarr[NUM_CHAN], *rxarr[NUM_CHAN];
+
+struct udma_user_info udma_tcb;
+
+void tx_complete(struct udma_chan *chan, void *handle, void *buf, unsigned size)
+{
+ udma_print_debug("completed tx packet %p, sent %d, size %d\n",
+ buf, *((unsigned long*)buf), size);
+ udma_tcb.tx_complete++;
+ udma_mem_block_free(part, buf);
+}
+
+void rx_complete(struct udma_chan *chan, void *handle, void *buf, unsigned size)
+{
+ int ret;
+
+ udma_print_debug("completed rx packet %p, received %d, size %d\n",
+ buf, *((unsigned long*)buf), size);
+ udma_tcb.rx_complete++;
+ ret = udma_chan_submit(rxchan, handle, rx_complete, buf, udma_tcb.buf_size);
+ if (ret < 0)
+ fprintf(stderr, "rx_complete: error submitting rx packet\n");
+}
+void udma_print_usage()
+{
+ udma_print_info("UDMA Test Application\n");
+ udma_print_info("Usage\n");
+ udma_print_info("udma_test id [test number] [buf size] [offset]\n");
+}
+
+void udma_parse_params(int argc, char *argv[])
+{
+ if (argc > 1)
+ udma_tcb.buf_size = atoi(argv[1]);
+ if (argc > 2)
+ udma_tcb.offset = atoi(argv[2]);
+
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned long mem_size = 8 * 1024 * 1024;
+ unsigned long tx_packets, loop;
+ int ret, i;
+ char *buf;
+ pthread_t thread1, thread2;
+ struct timeval start, end;
+ unsigned long long usecs;
+ struct timespec timeout = { 0, 0 };
+ struct timespec timeout1 = { 0, 0 };
+ char rxstr[10], txstr[10];
+
+
+ udma_init(NULL);
+ udma_print_info("*****Starting test, UDMA Init\n");
+ memset(&udma_tcb, 0, sizeof(udma_tcb));
+
+ udma_parse_params(argc, argv);
+
+ /* Set defaults for test-1 if not already set */
+ if (!udma_tcb.buf_size)
+ udma_tcb.buf_size = BUF_SIZE;
+ if (!udma_tcb.num_descs)
+ udma_tcb.num_descs = NUM_DESC_PER_CHAN;
+ udma_print_info("buf_size = %d, offset = %d descs = %d\n",
+ udma_tcb.buf_size,
+ udma_tcb.offset, udma_tcb.num_descs);
+
+ udma_mem_init(mem_size);
+ part = udma_mem_part_create(NUM_CHAN*(udma_tcb.num_descs * 2 + 16), udma_tcb.buf_size);
+
+ for (loop = 0; loop < NUM_CHAN; loop++)
+ {
+ tx_packets = 0;
+ udma_tcb.tx_complete = 0;
+ udma_tcb.rx_complete = 0;
+ part = udma_mem_part_create((udma_tcb.num_descs * 2 + 16), udma_tcb.buf_size);
+
+ snprintf(txstr, sizeof(txstr), "%s%d", "udmatx", loop);
+ snprintf(rxstr, sizeof(rxstr), "%s%d", "udmarx", loop);
+ udma_print_info("*****Creating %s and %s channels\n", txstr, rxstr);
+ txarr[loop] = udma_chan_create(txstr, UDMA_CHAN_TX,
+ udma_tcb.num_descs);
+ rxarr[loop] = udma_chan_create(rxstr, UDMA_CHAN_RX,
+ udma_tcb.num_descs);
+ txchan = txarr[loop];
+ rxchan = rxarr[loop];
+
+ if (!txchan || !rxchan) {
+ fprintf(stderr, "error opening udma channels %d\n", loop);
+ return 1;
+ }
+ udma_print_info("*****Running test on %s and %s channels\n", txstr, rxstr);
+ ret = udma_chan_get_fd(txchan);
+ udma_print_debug("get_fd for tx returned %d\n", ret);
+
+ ret = udma_chan_get_fd(rxchan);
+ udma_print_debug("get_fd for rx returned %d\n", ret);
+
+ gettimeofday(&start, NULL);
+
+ /* fill rx channel */
+ for (i = 0; i < udma_tcb.num_descs; i++) {
+ buf = udma_mem_block_alloc(part);
+ ret = udma_chan_submit(rxchan, part, rx_complete, buf,
+ udma_tcb.buf_size);
+ udma_chan_poll(rxchan, -1, &timeout);
+ if (ret < 0) {
+ fprintf(stderr, "error submitting rx packet\n");
+ continue;
+ }
+ }
+
+ for (i = 0; i < NUM_PACKETS; i++) {
+ do {
+ buf = udma_mem_block_alloc(part);
+ if (buf)
+ break;
+ udma_print_info("user space udma: did not get buf\n");
+ udma_chan_poll(txchan, -1, &timeout);
+ udma_chan_poll(rxchan, -1, &timeout);
+ } while (!buf);
+
+ *((unsigned long*)buf) = i;
+ ret = udma_chan_submit(txchan, part, tx_complete, buf,
+ udma_tcb.buf_size);
+ if (ret < 0) {
+ udma_print_info("error submitting pkt #%lu, ret = %d\n",
+ i, ret);
+ i--;
+ udma_mem_block_free(part, buf);
+ continue;
+ }
+ tx_packets++;
+ udma_print_debug("submitted tx packet %p, send %d\n", buf, i);
+ udma_chan_poll(txchan, -1, &timeout1);
+ udma_chan_poll(rxchan, -1, &timeout1);
+ }
+
+ gettimeofday(&end, NULL);
+
+ usecs = (end.tv_sec - start.tv_sec) * 1000000ULL;
+ usecs += end.tv_usec;
+ usecs -= start.tv_usec;
+
+ if (NUM_PACKETS >= 1000)
+ udma_print_info("total time = %llu usecs, %llu nsecs/packet\n",
+ usecs, usecs / (NUM_PACKETS / 1000));
+
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 1000;
+ for (i = 0; i < 1000; i++) {
+ if (udma_tcb.tx_complete == tx_packets &&
+ udma_tcb.rx_complete == tx_packets)
+ break;
+ udma_chan_poll(txchan, -1, &timeout);
+ udma_chan_poll(rxchan, -1, &timeout);
+ }
+
+ udma_print_info("Total-packets=%d tx-complete = %lu, rx-complete = %lu\n",
+ NUM_PACKETS, udma_tcb.tx_complete, udma_tcb.rx_complete);
+ udma_mem_part_destroy(part);
+ }
+ for (loop = 0; loop < NUM_CHAN; loop++)
+ {
+ udma_print_info("*****Deleting channel %s-%d %s-%d\n",
+ "udmatx", loop, "udmarx", loop);
+ udma_chan_destroy(rxarr[loop]);
+ udma_chan_destroy(txarr[loop]);
+ }
+ return;
+
+}