new file mode 100644
@@ -0,0 +1,1268 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * 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 Intel Corporation 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 <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_cycles.h>
+
+#include <rte_eventdev.h>
+#include "test.h"
+
+#define MAX_PORTS 16
+#define MAX_QIDS 16
+#define NUM_PACKETS (1<<18)
+
+struct test {
+ struct rte_mempool *mbuf_pool;
+ int ev;
+ int port[MAX_PORTS];
+ int qid[MAX_QIDS];
+ int nb_qids;
+};
+
+static inline struct rte_mbuf *
+rte_gen_arp(int portid, struct rte_mempool *mp)
+{
+ /*
+ * len = 14 + 46
+ * ARP, Request who-has 10.0.0.1 tell 10.0.0.2, length 46
+ */
+ static const uint8_t arp_request[] = {
+ /*0x0000:*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xa8,
+ 0x6b, 0xfd, 0x02, 0x29, 0x08, 0x06, 0x00, 0x01,
+ /*0x0010:*/ 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xec, 0xa8,
+ 0x6b, 0xfd, 0x02, 0x29, 0x0a, 0x00, 0x00, 0x01,
+ /*0x0020:*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /*0x0030:*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ struct rte_mbuf *m;
+ int pkt_len = sizeof(arp_request) - 1;
+
+ m = rte_pktmbuf_alloc(mp);
+ if (!m)
+ return 0;
+
+ memcpy((void *)((uint64_t)m->buf_addr + m->data_off),
+ arp_request, pkt_len);
+ rte_pktmbuf_pkt_len(m) = pkt_len;
+ rte_pktmbuf_data_len(m) = pkt_len;
+
+ RTE_SET_USED(portid);
+ /*
+ * Ignore MAC address for super-simple testing
+ * struct ether_addr mac_addr;
+ * rte_eth_macaddr_get(portid, &mac_addr);
+ * memcpy((void *)((uint64_t)m->buf_addr + m->data_off + 6),
+ * &mac_addr, 6);
+ */
+
+ return m;
+}
+
+/* initialization and config */
+static inline int
+init(struct test *t, int nb_queues, int nb_ports)
+{
+ struct rte_event_dev_config config = {
+ .nb_event_queues = nb_queues,
+ .nb_event_ports = nb_ports,
+ };
+ int ret, nevdevs = rte_event_dev_count();
+
+ void *temp = t->mbuf_pool; /* save and restore mbuf pool */
+
+ memset(t, 0, sizeof(*t));
+ t->mbuf_pool = temp;
+
+ if (nevdevs < 1) {
+ printf("%d: No Eventdev Devices Found\n", __LINE__);
+ return -1;
+ }
+
+ const char *eventdev_name = "evdev_sw0";
+
+ t->ev = rte_event_dev_get_dev_id(eventdev_name);
+ if (t->ev < 0) {
+ printf("%d: Eventdev %s not found - quitting.\n", __LINE__, eventdev_name);
+ return -1;
+ }
+
+ ret = rte_event_dev_configure(t->ev, &config);
+ if (ret < 0)
+ printf("%d: Error configuring device\n", __LINE__);
+ return ret;
+};
+
+static inline int
+create_ports(struct test *t, int num_ports)
+{
+ int i;
+ static const struct rte_event_port_conf conf = {
+ .dequeue_queue_depth = 32,
+ .enqueue_queue_depth = 64,
+ };
+
+ for (i = 0; i < num_ports; i++) {
+ if (rte_event_port_setup(t->ev, i, &conf) < 0) {
+ printf("Error setting up port %d\n", i);
+ return -1;
+ }
+ t->port[i] = i;
+ }
+
+ return 0;
+}
+
+static inline int
+create_atomic_qids(struct test *t, int num_qids)
+{
+ int i;
+
+ /* Q creation */
+ static const struct rte_event_queue_conf conf = {
+ .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL,
+ .nb_atomic_flows = 1024,
+ };
+
+ for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) {
+ if (rte_event_queue_setup(t->ev, i, &conf) < 0) {
+ printf("%d: error creating qid %d\n", __LINE__, i);
+ return -1;
+ }
+ t->qid[i] = i;
+ }
+ t->nb_qids += num_qids;
+
+ return 0;
+}
+
+static inline int
+create_ordered_qids(struct test *t, int num_qids)
+{
+ int i;
+
+ /* Q creation */
+ static const struct rte_event_queue_conf conf = {
+ .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL,
+ .nb_atomic_order_sequences = 1024,
+ };
+
+ for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) {
+ if (rte_event_queue_setup(t->ev, i, &conf) < 0) {
+ printf("%d: error creating qid %d\n", __LINE__, i);
+ return -1;
+ }
+ t->qid[i] = i;
+ }
+ t->nb_qids += num_qids;
+
+ return 0;
+}
+
+static inline int
+create_unordered_qids(struct test *t, int num_qids)
+{
+ int i;
+
+ /* Q creation */
+ static const struct rte_event_queue_conf conf = {
+ .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL,
+ };
+
+ for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) {
+ if (rte_event_queue_setup(t->ev, i, &conf) < 0) {
+ printf("%d: error creating qid %d\n", __LINE__, i);
+ return -1;
+ }
+ t->qid[i] = i;
+ }
+ t->nb_qids += num_qids;
+
+ return 0;
+}
+
+static inline int
+create_directed_qids(struct test *t, int num_qids, int ports[])
+{
+ int i;
+
+ /* Q creation */
+ static const struct rte_event_queue_conf conf = {
+ .priority = RTE_EVENT_QUEUE_PRIORITY_NORMAL,
+ .event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER,
+ };
+
+ for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) {
+ struct rte_event_queue_link link;
+
+ if (rte_event_queue_setup(t->ev, i, &conf) < 0) {
+ printf("%d: error creating qid %d\n", __LINE__, i);
+ return -1;
+ }
+ t->qid[i] = i;
+
+ link = (struct rte_event_queue_link){
+ t->qid[i],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL
+ };
+ if (rte_event_port_link(t->ev, ports[i - t->nb_qids], &link, 1) != 1) {
+ printf("%d: error creating link for qid %d\n",
+ __LINE__, i);
+ return -1;
+ }
+ }
+ t->nb_qids += num_qids;
+
+ return 0;
+}
+
+/* destruction */
+static inline int
+cleanup(struct test *t)
+{
+ rte_event_dev_stop(t->ev);
+ rte_event_dev_close(t->ev);
+ return 0;
+};
+
+/* run_prio_packet_test
+ * This performs a basic packet priority check on the test instance passed in.
+ * It is factored out of the main priority tests as the same tests must be
+ * performed to ensure prioritization of each type of QID.
+ *
+ * Requirements:
+ * - An initialized test structure, including mempool
+ * - t->port[0] is initialized for both Enq / Deq of packets to the QID
+ * - t->qid[0] is the QID to be tested
+ * - if LB QID, the CQ must be mapped to the QID.
+ */
+static int
+run_prio_packet_test(struct test *t)
+{
+ int err;
+ const uint32_t MAGIC_SEQN[] = {4711, 1234};
+ const uint32_t PRIORITY[] = {3, 0};
+ unsigned i;
+ for(i = 0; i < RTE_DIM(MAGIC_SEQN); i++) {
+ /* generate pkt and enqueue */
+ struct rte_event ev;
+ struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool);
+ if (!arp) {
+ printf("%d: gen of pkt failed\n", __LINE__);
+ return -1;
+ }
+ arp->seqn = MAGIC_SEQN[i];
+
+ ev = (struct rte_event){
+ .priority = PRIORITY[i],
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = t->qid[0],
+ .mbuf = arp
+ };
+ err = rte_event_enqueue(t->ev, t->port[0], &ev, 0);
+ if (err < 0) {
+ printf("%d: error failed to enqueue\n", __LINE__);
+ return -1;
+ }
+ }
+
+ rte_event_schedule(t->ev);
+
+ struct rte_event_dev_stats stats;
+ err = rte_event_dev_stats_get(t->ev, &stats);
+ if (err) {
+ printf("%d: error failed to get stats\n", __LINE__);
+ return -1;
+ }
+
+ if (stats.port_rx_pkts[t->port[0]] != 2) {
+ printf("%d: error stats incorrect for directed port\n", __LINE__);
+ rte_event_dev_dump(stdout, t->ev);
+ return -1;
+ }
+
+ struct rte_event ev, ev2;
+ uint32_t deq_pkts;
+ deq_pkts = rte_event_dequeue(t->ev, t->port[0], &ev, 0);
+ if (deq_pkts != 1) {
+ printf("%d: error failed to deq\n", __LINE__);
+ rte_event_dev_dump(stdout, t->ev);
+ return -1;
+ }
+ if(ev.mbuf->seqn != MAGIC_SEQN[1]) {
+ printf("%d: first packet out not highest priority\n", __LINE__);
+ rte_event_dev_dump(stdout, t->ev);
+ return -1;
+ }
+ rte_pktmbuf_free(ev.mbuf);
+
+ deq_pkts = rte_event_dequeue(t->ev, t->port[0], &ev2, 0);
+ if (deq_pkts != 1) {
+ printf("%d: error failed to deq\n", __LINE__);
+ rte_event_dev_dump(stdout, t->ev);
+ return -1;
+ }
+ if(ev2.mbuf->seqn != MAGIC_SEQN[0]) {
+ printf("%d: second packet out not lower priority\n", __LINE__);
+ rte_event_dev_dump(stdout, t->ev);
+ return -1;
+ }
+ rte_pktmbuf_free(ev2.mbuf);
+
+ cleanup(t);
+ return 0;
+}
+
+static int
+test_single_directed_packet(struct test *t)
+{
+ const int rx_enq = 0;
+ const int wrk_enq = 2;
+ int err;
+
+ /* Create instance with 3 directed QIDs going to 3 ports */
+ if (init(t, 3, 3) < 0 ||
+ create_ports(t, 3) < 0 ||
+ create_directed_qids(t, 3, t->port) < 0)
+ return -1;
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ /************** FORWARD ****************/
+ struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool);
+ struct rte_event ev = {
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = wrk_enq,
+ .mbuf = arp,
+ };
+
+ if (!arp) {
+ printf("%d: gen of pkt failed\n", __LINE__);
+ return -1;
+ }
+
+ const uint32_t MAGIC_SEQN = 4711;
+ arp->seqn = MAGIC_SEQN;
+
+ /* generate pkt and enqueue */
+ err = rte_event_enqueue(t->ev, rx_enq, &ev, 0);
+ if (err < 0) {
+ printf("%d: error failed to enqueue\n", __LINE__);
+ return -1;
+ }
+
+ /* Run schedule() as dir packets may need to be re-ordered */
+ if (rte_event_schedule(t->ev) < 0) {
+ printf("%d: Error with schedule call\n", __LINE__);
+ return -1;
+ }
+
+ struct rte_event_dev_stats stats;
+ err = rte_event_dev_stats_get(t->ev, &stats);
+ if (err) {
+ printf("%d: error failed to get stats\n", __LINE__);
+ return -1;
+ }
+
+ if (stats.port_rx_pkts[rx_enq] != 1) {
+ printf("%d: error stats incorrect for directed port\n", __LINE__);
+ return -1;
+ }
+
+ uint32_t deq_pkts;
+ deq_pkts = rte_event_dequeue(t->ev, wrk_enq, &ev, 1);
+ if (deq_pkts != 1) {
+ printf("%d: error failed to deq\n", __LINE__);
+ return -1;
+ }
+
+ err = rte_event_dev_stats_get(t->ev, &stats);
+ if (stats.port_rx_pkts[wrk_enq] != 0 &&
+ stats.port_rx_pkts[wrk_enq] != 1) {
+ printf("%d: error directed stats post-dequeue\n", __LINE__);
+ return -1;
+ }
+
+ if (ev.mbuf->seqn != MAGIC_SEQN) {
+ printf("%d: error magic sequence number not dequeued\n", __LINE__);
+ return -1;
+ }
+
+ rte_pktmbuf_free(ev.mbuf);
+ cleanup(t);
+ return 0;
+}
+
+static int
+test_overload_trip(struct test *t)
+{
+ int err;
+
+ /* Create instance with 3 directed QIDs going to 3 ports */
+ if (init(t, 1, 1) < 0 ||
+ create_ports(t, 1) < 0 ||
+ create_atomic_qids(t, 1) < 0)
+ return -1;
+
+ struct rte_event_queue_link link = {t->qid[0],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ int ret = rte_event_port_link(t->ev, t->port[0], &link, 1);
+ if (ret != 1) {
+ printf("%d: error mapping lb qid0\n", __LINE__);
+ return -1;
+ }
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool);
+ if (!arp) {
+ printf("%d: gen of pkt failed\n", __LINE__);
+ return -1;
+ }
+
+ /* 512 packets is threshold
+ * iters 0 - 511 is 512 packets, then overload will be flagged
+ * iter 512 (the 513th pkt) is the first refused NEW packet */
+ const uint32_t THRES = (256+1);
+ uint32_t i;
+ for (i = 0; i < THRES; i++) {
+ struct rte_event ev = {
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = t->qid[0],
+ .mbuf = arp,
+ };
+ err = rte_event_enqueue(t->ev, 0, &ev, 0);
+ if(i == THRES-1) {
+ if(err != -ENOSPC) {
+ printf("%d: overload trip didn't cause NEW pkt enq fail\n", __LINE__);
+ return -1;
+ }
+ else {
+ //printf("iter %d -ENOSPC returned for new enq as expected.\n", i);
+ }
+ } else {
+ if (err < 0) {
+ printf("%d: error failed to enqueue\n", __LINE__);
+ return -1;
+ }
+ }
+ }
+
+ for (i = 0; i < THRES; i++) {
+ if (rte_event_schedule(t->ev) < 0) {
+ printf("%d: Error with schedule call\n", __LINE__);
+ return -1;
+ }
+
+ uint32_t deq_pkts;
+ struct rte_event ev;
+ deq_pkts = rte_event_dequeue(t->ev, 0, &ev, 1);
+
+ /* i == THRES-1 *should* fail to deq, due to NEW pkt rejection
+ * when enqueue is attempted in overload mode */
+ if (i == (THRES-1) && deq_pkts == 0)
+ break;
+
+ if (deq_pkts != 1) {
+ printf("%d: warning failed to deq event i = %d\n",
+ __LINE__, i);
+ //return -1;
+ }
+ }
+
+ rte_pktmbuf_free(arp);
+ cleanup(t);
+ return 0;
+}
+
+static int
+test_directed_overload(struct test *t)
+{
+ int err;
+
+ /* Create instance with 3 directed QIDs going to 3 ports */
+ if (init(t, 1, 1) < 0 ||
+ create_ports(t, 1) < 0 ||
+ create_directed_qids(t, 1, t->port) < 0)
+ return -1;
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ /* 512 packets is threshold
+ * iters 0 - 511 is 512 packets, then overload will be flagged
+ * iter 512 (the 513th pkt) is the first refused NEW packet */
+ const uint32_t THRES = (256+1);
+ uint32_t i;
+ for (i = 0; i < THRES; i++) {
+ struct rte_event ev = {
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = t->qid[0],
+ .event = (uintptr_t)i,
+ };
+ err = rte_event_enqueue(t->ev, 0, &ev, 0);
+ if(i == THRES-1) {
+ if(err != -ENOSPC) {
+ printf("%d: overload trip didn't cause NEW pkt enq fail\n", __LINE__);
+ //return -1;
+ }
+ else {
+ //printf("iter %d -ENOSPC returned for new enq as expected.\n", i);
+ }
+ } else {
+ if (err < 0) {
+ printf("%d: error failed to enqueue\n", __LINE__);
+ return -1;
+ }
+ }
+ }
+
+ if (rte_event_schedule(t->ev) < 0) {
+ printf("%d: Error with schedule call\n", __LINE__);
+ return -1;
+ }
+
+ uint32_t pkt_deq_cntr = 0;
+ for (i = 0; i < THRES; i++) {
+ if (rte_event_schedule(t->ev) < 0) {
+ printf("%d: Error with schedule call\n", __LINE__);
+ return -1;
+ }
+
+ int32_t deq_pkts;
+ struct rte_event ev;
+ deq_pkts = rte_event_dequeue(t->ev, 0, &ev, 1);
+
+ /* i == THRES-1 *should* fail to deq, due to NEW pkt rejection
+ * when enqueue is attempted in overload mode */
+ if (i == (THRES-1) && deq_pkts == 0)
+ break;
+
+ if (deq_pkts != 1) {
+ printf("%d: warning failed to deq (iter = %d), ret %d. Dumping stats\n",
+ __LINE__, i, deq_pkts);
+ rte_event_dev_dump(stdout, t->ev);
+ return -1;
+ }
+ pkt_deq_cntr += deq_pkts;
+ }
+
+ cleanup(t);
+ return 0;
+}
+
+
+static int
+test_priority_directed(struct test *t)
+{
+ if (init(t, 1, 1) < 0 ||
+ create_ports(t, 1) < 0 ||
+ create_directed_qids(t, 1, t->port) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ return run_prio_packet_test(t);
+}
+
+static int
+test_priority_atomic(struct test *t)
+{
+ if (init(t, 1, 1) < 0 ||
+ create_ports(t, 1) < 0 ||
+ create_atomic_qids(t, 1) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ /* map the QID */
+ struct rte_event_queue_link link = {t->qid[0],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ if (rte_event_port_link(t->ev, t->port[0], &link, 1) != 1) {
+ printf("%d: error mapping qid to port\n", __LINE__);
+ return -1;
+ }
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ return run_prio_packet_test(t);
+}
+
+static int
+test_priority_ordered(struct test *t)
+{
+ if (init(t, 1, 1) < 0 ||
+ create_ports(t, 1) < 0 ||
+ create_ordered_qids(t, 1) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ /* map the QID */
+ struct rte_event_queue_link link = {t->qid[0],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ if (rte_event_port_link(t->ev, t->port[0], &link, 1) != 1) {
+ printf("%d: error mapping qid to port\n", __LINE__);
+ return -1;
+ }
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ return run_prio_packet_test(t);
+}
+
+static int
+test_priority_unordered(struct test *t)
+{
+ if (init(t, 1, 1) < 0 ||
+ create_ports(t, 1) < 0 ||
+ create_unordered_qids(t, 1) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ /* map the QID */
+ struct rte_event_queue_link link = {t->qid[0],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ if (rte_event_port_link(t->ev, t->port[0], &link, 1) != 1) {
+ printf("%d: error mapping qid to port\n", __LINE__);
+ return -1;
+ }
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ return run_prio_packet_test(t);
+}
+
+static int
+burst_packets(struct test *t)
+{
+ /************** CONFIG ****************/
+ uint32_t i;
+ int err;
+ int ret;
+
+ /* Create instance with 4 ports and 2 queues */
+ if (init(t, 2, 2) < 0 ||
+ create_ports(t, 2) < 0 ||
+ create_atomic_qids(t, 2) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ /* CQ mapping to QID */
+ struct rte_event_queue_link link = {t->qid[0],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ ret = rte_event_port_link(t->ev, t->port[0], &link, 1);
+ if (ret != 1) {
+ printf("%d: error mapping lb qid0\n", __LINE__);
+ return -1;
+ }
+ link.queue_id = t->qid[1];
+ ret = rte_event_port_link(t->ev, t->port[1], &link, 1);
+ if (ret != 1) {
+ printf("%d: error mapping lb qid1\n", __LINE__);
+ return -1;
+ }
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ /************** FORWARD ****************/
+ const uint32_t rx_port = 0;
+ const uint32_t NUM_PKTS = 2;
+
+ for (i = 0; i < NUM_PKTS; i++) {
+ struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool);
+ if (!arp) {
+ printf("%d: error generating pkt\n" , __LINE__);
+ return -1;
+ }
+
+ struct rte_event ev = {
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = i % 2,
+ .flow_id = i % 3,
+ .mbuf = arp,
+ };
+ /* generate pkt and enqueue */
+ err = rte_event_enqueue(t->ev, t->port[rx_port], &ev, 0);
+ if (err < 1) {
+ printf("%d: Failed to enqueue\n", __LINE__);
+ return -1;
+ }
+ }
+ int16_t pkts = rte_event_schedule(t->ev);
+
+ RTE_SET_USED(pkts);
+
+ /* Check stats for all NUM_PKTS arrived to sched core */
+ struct rte_event_dev_stats stats;
+
+ err = rte_event_dev_stats_get(t->ev, &stats);
+ if (err) {
+ printf("%d: failed to get stats\n", __LINE__);
+ return -1;
+ }
+ if (stats.rx_pkts != NUM_PKTS || stats.tx_pkts != NUM_PKTS) {
+ printf("%d: Sched core didn't receive all %d pkts\n", __LINE__, NUM_PKTS);
+ rte_event_dev_dump(stdout, t->ev);
+ return -1;
+ }
+
+ uint32_t deq_pkts;
+ int p;
+
+ deq_pkts = 0;
+ /******** DEQ QID 1 *******/
+ do {
+ struct rte_event ev;
+ p = rte_event_dequeue(t->ev, t->port[0], &ev, 0);
+ deq_pkts += p;
+ rte_pktmbuf_free(ev.mbuf);
+ } while (p);
+
+ if (deq_pkts != NUM_PKTS/2) {
+ printf("%d: Half of NUM_PKTS didn't arrive at port 1\n", __LINE__);
+ return -1;
+ }
+
+ /******** DEQ QID 2 *******/
+ deq_pkts = 0;
+ do {
+ struct rte_event ev;
+ p = rte_event_dequeue(t->ev, t->port[1], &ev, 0);
+ deq_pkts += p;
+ rte_pktmbuf_free(ev.mbuf);
+ } while (p);
+ if (deq_pkts != NUM_PKTS/2) {
+ printf("%d: Half of NUM_PKTS didn't arrive at port 2\n", __LINE__);
+ return -1;
+ }
+
+ cleanup(t);
+ return 0;
+}
+
+static int
+load_balancing(struct test *t)
+{
+ const int rx_enq = 0;
+ int err;
+ uint32_t i;
+
+ if (init(t, 1, 4) < 0 ||
+ create_ports(t, 4) < 0 ||
+ create_atomic_qids(t, 1) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ struct rte_event_queue_link link = {t->qid[0],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ for (i = 0; i < 3; i++) {
+ /* map port 1 - 3 inclusive */
+ if (rte_event_port_link(t->ev, t->port[i+1], &link, 1) != 1) {
+ printf("%d: error mapping qid to port %d\n", __LINE__, i);
+ return -1;
+ }
+ }
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ /************** FORWARD ****************/
+ /*
+ * Create a set of flows that test the load-balancing operation of the
+ * implementation. Fill CQ 0 and 1 with flows 0 and 1, and test
+ * with a new flow, which should be sent to the 3rd mapped CQ
+ */
+ static uint32_t flows[] = {0, 1, 1, 0, 0, 2, 2, 0, 2};
+#define PKT_NUM (sizeof(flows) / sizeof(flows[0]))
+ for (i = 0; i < PKT_NUM; i++) {
+ struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool);
+ if (!arp) {
+ printf("%d: gen of pkt failed\n", __LINE__);
+ return -1;
+ }
+
+ struct rte_event ev = {
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = t->qid[0],
+ .flow_id = flows[i],
+ .mbuf = arp,
+ };
+ /* generate pkt and enqueue */
+ err = rte_event_enqueue(t->ev, t->port[rx_enq], &ev, 0);
+ if (err < 1) {
+ printf("%d: Failed to enqueue\n", __LINE__);
+ return -1;
+ }
+ }
+
+ rte_event_schedule(t->ev);
+
+ struct rte_event_dev_stats stats;
+ err = rte_event_dev_stats_get(t->ev, &stats);
+ if (err) {
+ printf("%d: failed to get stats\n", __LINE__);
+ return -1;
+ }
+
+ if (stats.port_inflight[1] != 4) {
+ printf("%d:%s: port 1 inflight not correct\n", __LINE__, __func__);
+ return -1;
+ }
+ if (stats.port_inflight[2] != 2) {
+ printf("%d:%s: port 2 inflight not correct\n", __LINE__, __func__);
+ return -1;
+ }
+ if (stats.port_inflight[3] != 3) {
+ printf("%d:%s: port 3 inflight not correct\n", __LINE__, __func__);
+ return -1;
+ }
+
+ cleanup(t);
+ return 0;
+}
+
+static int
+invalid_qid(struct test *t)
+{
+ struct rte_event_dev_stats stats;
+ const int rx_enq = 0;
+ int err;
+ uint32_t i;
+
+ if (init(t, 1, 4) < 0 ||
+ create_ports(t, 4) < 0 ||
+ create_atomic_qids(t, 1) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ /* CQ mapping to QID */
+ for(i = 0; i < 4; i++) {
+ struct rte_event_queue_link link = {t->qid[0],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ err = rte_event_port_link(t->ev, t->port[i], &link, 1);
+ if (err != 1) {
+ printf("%d: error mapping port 1 qid\n", __LINE__);
+ return -1;
+ }
+ }
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ /*
+ * Send in a packet with an invalid qid to the scheduler.
+ * We should see the packed enqueued OK, but the inflights for
+ * that packet should not be incremented, and the rx_dropped
+ * should be incremented.
+ */
+ static uint32_t flows1[] = {20};
+
+#define PKT_NUM1 (sizeof(flows1) / sizeof(flows1[0]))
+
+ for (i = 0; i < PKT_NUM1; i++) {
+ struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool);
+ if (!arp) {
+ printf("%d: gen of pkt failed\n", __LINE__);
+ return -1;
+ }
+
+ struct rte_event ev = {
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = t->qid[0] + flows1[i],
+ .flow_id = i,
+ .mbuf = arp,
+ };
+ /* generate pkt and enqueue */
+ err = rte_event_enqueue(t->ev, t->port[rx_enq], &ev, 0);
+ if (err < 1) {
+ printf("%d: Failed to enqueue\n", __LINE__);
+ return -1;
+ }
+ }
+
+ /* call the scheduler */
+ int16_t pkts = rte_event_schedule(t->ev);
+ RTE_SET_USED(pkts);
+
+ err = rte_event_dev_stats_get(t->ev, &stats);
+ if (err) {
+ printf("%d: failed to get stats\n", __LINE__);
+ return -1;
+ }
+
+ /*
+ * Now check the resulting inflights on the port, and the rx_dropped.
+ */
+ if (stats.port_inflight[0] != 0) {
+ printf("%d:%s: port 1 inflight count not correct\n", __LINE__, __func__);
+ rte_event_dev_dump(stdout, 0);
+ return -1;
+ }
+ if (stats.port_rx_dropped[0] != 1) {
+ printf("%d:%s: port 1 drops\n", __LINE__, __func__);
+ rte_event_dev_dump(stdout, 0);
+ return -1;
+ }
+ /* each packet drop should only be counted in one place - port or dev */
+ if (stats.rx_dropped != 0) {
+ printf("%d:%s: port 1 dropped count not correct\n", __LINE__, __func__);
+ rte_event_dev_dump(stdout, 0);
+ return -1;
+ }
+
+ cleanup(t);
+ return 0;
+}
+
+static int
+worker_loopback_worker_fn(void *arg)
+{
+ struct test *t = arg;
+ uint8_t port = t->port[1];
+ int count = 0;
+ int err;
+
+ /*
+ * Takes packets from the input port and then loops them back through
+ * the Queue Manager. Each packet gets looped through QIDs 0-8, 16 times,
+ * so each packet goes through 8*16 = 128 times.
+ */
+ printf("%d: \tWorker function started\n", __LINE__);
+ while (count < NUM_PACKETS) {
+#define BURST_SIZE 32
+ struct rte_event ev[BURST_SIZE];
+ uint16_t i, nb_rx = rte_event_dequeue(t->ev, port, ev, BURST_SIZE);
+ if (nb_rx == 0) {
+ rte_pause();
+ continue;
+ }
+
+ for (i = 0; i < nb_rx; i++) {
+ ev[i].queue_id++;
+ if (ev[i].queue_id != 8) {
+ ev[i].operation = RTE_EVENT_OP_FORWARD;
+ err = rte_event_enqueue(t->ev, port, &ev[i], 0);
+ if (err <= 0) {
+ printf("%d: Can't enqueue FWD!!\n", __LINE__);
+ return -1;
+ }
+ continue;
+ }
+
+ ev[i].queue_id = 0;
+ ev[i].mbuf->udata64++;
+ if (ev[i].mbuf->udata64 != 16) {
+ ev[i].operation = RTE_EVENT_OP_FORWARD;
+ err = rte_event_enqueue(t->ev, port, &ev[i], 0);
+ if (err <= 0) {
+ printf("%d: Can't enqueue FWD!!\n", __LINE__);
+ return -1;
+ }
+ continue;
+ }
+ /* we have hit 16 iterations through system - drop */
+ rte_pktmbuf_free(ev[i].mbuf);
+ count++;
+ ev[i].operation = RTE_EVENT_OP_DROP;
+ err = rte_event_enqueue(t->ev, port, &ev[i], 0);
+ if(err != 1) {
+ printf("%d drop enqueue failed\n", __LINE__);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+worker_loopback_producer_fn(void *arg)
+{
+ struct test *t = arg;
+ uint8_t port = t->port[0];
+ uint64_t count = 0;
+
+ printf("%d: \tProducer function started\n", __LINE__);
+ while (count < NUM_PACKETS) {
+ struct rte_mbuf *m = rte_pktmbuf_alloc(t->mbuf_pool);
+ if (m == NULL) {
+ printf("%d: Error allocating mbuf\n", __LINE__);
+ return -1;
+ }
+ m->udata64 = 0;
+
+ struct rte_event ev = {
+ .operation = RTE_EVENT_OP_NEW,
+ .queue_id = t->qid[0],
+ .flow_id = (uintptr_t)m & 0xFFFF,
+ .mbuf = m,
+ };
+
+ while (rte_event_enqueue(t->ev, port, &ev, 0) != 1)
+ rte_pause();
+
+ count++;
+ }
+
+ return 0;
+}
+
+static int
+worker_loopback(struct test *t)
+{
+ /* use a single producer core, and a worker core to see what happens
+ * if the worker loops packets back multiple times
+ */
+ struct rte_event_dev_stats stats;
+ uint64_t print_cycles = 0, cycles = 0;
+ uint64_t tx_pkts = 0;
+ int err;
+ int w_lcore, p_lcore;
+ uint32_t i;
+
+ if (init(t, 8, 2) < 0 ||
+ create_ports(t, 2) < 0 ||
+ create_atomic_qids(t, 8) < 0) {
+ printf("%d: Error initialising device\n", __LINE__);
+ return -1;
+ }
+
+ /* CQ mapping to QID */
+ for(i = 0; i < 8; i++) {
+ struct rte_event_queue_link link = {t->qid[i],
+ RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL };
+ err = rte_event_port_link(t->ev, t->port[1], &link, 1);
+ if (err != 1) {
+ printf("%d: error mapping port 2 qid %d\n", __LINE__, i);
+ return -1;
+ }
+ }
+
+ if (rte_event_dev_start(t->ev) < 0) {
+ printf("%d: Error with start call\n", __LINE__);
+ return -1;
+ }
+
+ p_lcore = rte_get_next_lcore(
+ /* start core */ -1,
+ /* skip master */ 1,
+ /* wrap */ 0);
+ w_lcore = rte_get_next_lcore(p_lcore, 1, 0);
+
+ rte_eal_remote_launch(worker_loopback_producer_fn, t, p_lcore);
+ rte_eal_remote_launch(worker_loopback_worker_fn, t, w_lcore);
+
+ print_cycles = cycles = rte_get_timer_cycles();
+ while (rte_eal_get_lcore_state(p_lcore) != FINISHED ||
+ rte_eal_get_lcore_state(w_lcore) != FINISHED) {
+
+ rte_event_schedule(t->ev);
+
+ uint64_t new_cycles = rte_get_timer_cycles();
+
+ if (new_cycles - print_cycles > rte_get_timer_hz()) {
+ rte_event_dev_stats_get(t->ev, &stats);
+ printf("%d: \tSched Rx = %" PRIu64 ", Tx = %" PRIu64 "\n",
+ __LINE__, stats.rx_pkts, stats.tx_pkts);
+
+ print_cycles = new_cycles;
+ }
+ if (new_cycles - cycles > rte_get_timer_hz() * 3) {
+ rte_event_dev_stats_get(t->ev, &stats);
+ if (stats.tx_pkts == tx_pkts) {
+ rte_event_dev_dump(stdout, t->ev);
+ printf("%d: \nNo schedules for seconds, deadlock\n", __LINE__);
+ return -1;
+ }
+ tx_pkts = stats.tx_pkts;
+ cycles = new_cycles;
+ }
+ }
+
+ rte_eal_mp_wait_lcore();
+
+ //rte_event_dev_dump(stdout, 0);
+
+ cleanup(t);
+ return 0;
+}
+
+static struct rte_mempool *eventdev_func_mempool;
+
+static int
+test_eventdev(void)
+{
+ struct test *t = malloc(sizeof(struct test));
+ int ret;
+
+ /* Only create mbuf pool once, reuse for each test run */
+ if (!eventdev_func_mempool) {
+ eventdev_func_mempool = rte_pktmbuf_pool_create("EVDEV_SA_MBUF_POOL",
+ (1<<16), /* size */
+ 32 /*MBUF_CACHE_SIZE*/,
+ 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE,
+ rte_socket_id());
+ if (!eventdev_func_mempool) {
+ printf("ERROR creating mempool\n");
+ return -1;
+ }
+ }
+ t->mbuf_pool = eventdev_func_mempool;
+
+ printf("*** Running Single Directed Packet test...\n");
+ ret = test_single_directed_packet(t);
+ if (ret != 0) {
+ printf("ERROR - Single Directed Packet test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Overload Trip test...\n");
+ ret = test_overload_trip(t);
+ if (ret != 0) {
+ printf("ERROR - Overload Trip test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Directed Overload test...\n");
+ ret = test_directed_overload(t);
+ if (ret != 0) {
+ printf("ERROR - Directed Overload test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Prioritized Directed test...\n");
+ ret = test_priority_directed(t);
+ if (ret != 0) {
+ printf("ERROR - Prioritized Directed test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Prioritized Atomic test...\n");
+ ret = test_priority_atomic(t);
+ if (ret != 0) {
+ printf("ERROR - Prioritized Atomic test FAILED.\n");
+ return ret;
+ }
+
+ printf("*** Running Prioritized Ordered test...\n");
+ ret = test_priority_ordered(t);
+ if (ret != 0) {
+ printf("ERROR - Prioritized Ordered test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Prioritized Unordered test...\n");
+ ret = test_priority_unordered(t);
+ if (ret != 0) {
+ printf("ERROR - Prioritized Unordered test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Burst Packets test...\n");
+ ret = burst_packets(t);
+ if (ret != 0) {
+ printf("ERROR - Burst Packets test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Load Balancing test...\n");
+ ret = load_balancing(t);
+ if (ret != 0) {
+ printf("ERROR - Load Balancing test FAILED.\n");
+ return ret;
+ }
+ printf("*** Running Invalid QID test...\n");
+ ret = invalid_qid(t);
+ if (ret != 0) {
+ printf("ERROR - Invalid QID test FAILED.\n");
+ return ret;
+ }
+ if (rte_lcore_count() >= 3) {
+ printf("*** Running Worker loopback test...\n");
+ ret = worker_loopback(t);
+ if (ret != 0) {
+ printf("ERROR - Worker loopback test FAILED.\n");
+ return ret;
+ }
+ } else {
+ printf("### Not enough cores for worker loopback test. \n");
+ printf("### Need at least 3 cores for test.\n");
+ }
+ /* Free test instance, leaving mempool initialized, and a pointer to it
+ * in the static eventdev_func_mempool variable. It is re-used on re-runs */
+ free(t);
+
+ return 0;
+}
+
+REGISTER_TEST_COMMAND(eventdev_func_autotest, test_eventdev);
new file mode 100644
@@ -0,0 +1,557 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * 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 Intel Corporation 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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include "test.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include <rte_eventdev.h>
+#include <rte_lcore.h>
+#include <rte_mbuf.h>
+
+typedef enum eventdev_api_ut_ids_s {
+ EVENTDEV_API_UT_001 = 1,
+ EVENTDEV_API_UT_002,
+ EVENTDEV_API_UT_003,
+ EVENTDEV_API_UT_004,
+ EVENTDEV_API_UT_005,
+ EVENTDEV_API_UT_006,
+ EVENTDEV_API_UT_007,
+ EVENTDEV_API_UT_008,
+ EVENTDEV_API_UT_009,
+ EVENTDEV_API_UT_010,
+ EVENTDEV_API_UT_011,
+ EVENTDEV_API_UT_012,
+ EVENTDEV_API_UT_013,
+ EVENTDEV_API_UT_014,
+ EVENTDEV_API_UT_015,
+ EVENTDEV_API_UT_016,
+ EVENTDEV_API_UT_017,
+ EVENTDEV_API_UT_MAX
+} eventdev_api_ut_ids_t;
+
+typedef enum eventdev_tc_status_s {
+ TC_FAILED,
+ TC_PASSED
+} eventdev_tc_status_t;
+
+typedef struct eventdev_api_ut_status_s {
+ bool executed;
+ eventdev_tc_status_t status;
+} eventdev_api_ut_status_t;
+
+eventdev_api_ut_status_t api_ut_status[EVENTDEV_API_UT_MAX];
+
+#define CONFIG_NB_EVENT_QUEUES 2
+#define CONFIG_NB_EVENT_PORTS 2
+#define CONFIG_NB_EVENT_LIMIT 128
+
+uint8_t queues[CONFIG_NB_EVENT_QUEUES];
+uint8_t ports[CONFIG_NB_EVENT_PORTS];
+
+/* FIXME: Check that dependent tests have executed */
+
+static int test_EVENTDEV_API_UT_001_rte_event_dev_count(void)
+{
+ uint8_t count = rte_event_dev_count();
+
+ if (count == 1) {
+ api_ut_status[EVENTDEV_API_UT_001].status = TC_PASSED;
+ return 0;
+ } else {
+ api_ut_status[EVENTDEV_API_UT_001].status = TC_FAILED;
+ return 1;
+ }
+}
+
+static int test_EVENTDEV_API_UT_002_rte_event_dev_get_dev_id(void)
+{
+ int8_t id;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ if (id < 0) {
+ api_ut_status[EVENTDEV_API_UT_002].status = TC_FAILED;
+ return 1;
+ }
+
+ id = rte_event_dev_get_dev_id("evdev_abcd123");
+
+ if (id >= 0) {
+ api_ut_status[EVENTDEV_API_UT_002].status = TC_FAILED;
+ return 1;
+ }
+
+ api_ut_status[EVENTDEV_API_UT_002].status = TC_PASSED;
+ return 0;
+}
+
+static int test_EVENTDEV_API_UT_003_rte_event_dev_info_get(void)
+{
+ struct rte_event_dev_info info;
+ int8_t id;
+ int ret;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ ret = rte_event_dev_info_get(id, &info);
+ if (ret)
+ goto fail;
+
+ if (strncmp(info.driver_name, "evdev_sw", sizeof("evdev_sw")) != 0)
+ goto fail;
+
+ /* FIXME: Add checks for remaining fields */
+
+ api_ut_status[EVENTDEV_API_UT_003].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_003].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_004_rte_event_dev_configure(void)
+{
+ struct rte_event_dev_config config;
+ int8_t id;
+ int ret;
+
+ api_ut_status[EVENTDEV_API_UT_004].executed = true;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ config.nb_event_queues = CONFIG_NB_EVENT_QUEUES; /* FIXME: Test max */
+ config.nb_event_ports = CONFIG_NB_EVENT_PORTS; /* FIXME: Test max */
+ config.nb_events_limit = CONFIG_NB_EVENT_LIMIT; /* FIXME: Test max */
+ config.dequeue_wait_ns = 0; /* FIXME: Test max */
+
+ ret = rte_event_dev_configure(id, &config);
+ if (ret)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_004].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_004].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_005_rte_event_queue_count_pre(void)
+{
+ int8_t id;
+ uint8_t count;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ count = rte_event_queue_count(id);
+ if (count != CONFIG_NB_EVENT_QUEUES)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_005].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_005].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_006_rte_event_queue_setup(void)
+{
+ struct rte_event_queue_conf config;
+ int8_t id;
+ int ret;
+
+ api_ut_status[EVENTDEV_API_UT_006].executed = true;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ config.event_queue_cfg = 0;
+ config.priority = 0;
+
+ queues[0] = 0;
+
+ ret = rte_event_queue_setup(id, queues[0], &config);
+ if (ret < 0)
+ goto fail;
+
+ config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER;
+ config.priority = 0;
+
+ queues[1] = 1;
+
+ ret = rte_event_queue_setup(id, queues[1], &config);
+ if (ret < 0)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_006].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_006].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_007_rte_event_queue_count_post(void)
+{
+ int8_t id;
+ uint8_t count;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ if (!api_ut_status[EVENTDEV_API_UT_006].executed)
+ test_EVENTDEV_API_UT_006_rte_event_queue_setup();
+ if (api_ut_status[EVENTDEV_API_UT_006].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ count = rte_event_queue_count(id);
+ if (count != CONFIG_NB_EVENT_QUEUES)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_007].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_007].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_008_rte_event_port_count_pre(void)
+{
+ int8_t id;
+ uint8_t count;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ count = rte_event_port_count(id);
+ if (count != CONFIG_NB_EVENT_PORTS)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_008].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_008].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_009_rte_event_port_setup(void)
+{
+ struct rte_event_port_conf config;
+ int8_t id;
+ int ret;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_009].executed = true;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ config.dequeue_queue_depth = 4;
+ config.enqueue_queue_depth = 4;
+ config.new_event_threshold = 64;
+
+ ports[0] = 0;
+
+ ret = rte_event_port_setup(id, ports[0], &config);
+ if (ret < 0)
+ goto fail;
+
+ config.dequeue_queue_depth = 4;
+ config.enqueue_queue_depth = 4;
+ config.new_event_threshold = 64;
+
+ ports[1] = 1;
+
+ ret = rte_event_port_setup(id, ports[1], &config);
+ if (ret < 0)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_009].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_009].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_010_rte_event_port_count_post(void)
+{
+ int8_t id;
+ uint8_t count;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ if (!api_ut_status[EVENTDEV_API_UT_009].executed)
+ test_EVENTDEV_API_UT_009_rte_event_port_setup();
+ if (api_ut_status[EVENTDEV_API_UT_009].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ count = rte_event_port_count(id);
+ if (count != CONFIG_NB_EVENT_PORTS)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_010].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_010].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_011_rte_event_dev_start(void)
+{
+ int8_t id;
+ int ret;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ ret = rte_event_dev_start(id);
+ if (ret != 0)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_011].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_011].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_012_rte_event_port_link(void)
+{
+ struct rte_event_queue_link link;
+ int8_t id;
+ int ret;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ if (!api_ut_status[EVENTDEV_API_UT_006].executed)
+ test_EVENTDEV_API_UT_006_rte_event_queue_setup();
+ if (api_ut_status[EVENTDEV_API_UT_006].status == TC_FAILED)
+ goto fail;
+
+ if (!api_ut_status[EVENTDEV_API_UT_009].executed)
+ test_EVENTDEV_API_UT_009_rte_event_port_setup();
+ if (api_ut_status[EVENTDEV_API_UT_009].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ link.queue_id = queues[0];
+ link.priority = 0;
+
+ /* Connect port to previously configured scheduled queue */
+ ret = rte_event_port_link(id, ports[0], &link, 1);
+ if (ret != 1) {
+ printf("%d: failed here\n", __LINE__);
+ goto fail;
+ }
+
+ /* Check idempotency of re-linking port to queues[0] */
+ ret = rte_event_port_link(id, ports[0], &link, 1);
+ if (ret != 1) {
+ printf("%d: failed here\n", __LINE__);
+ goto fail;
+ }
+
+ link.queue_id = queues[1];
+ link.priority = 0;
+
+ /* Attempt to connect to FIFO queue as well */
+ ret = rte_event_port_link(id, ports[0], &link, 1);
+ if (ret == 1) {
+ printf("%d: failed here\n", __LINE__);
+ goto fail;
+ }
+
+ link.queue_id = queues[1];
+ link.priority = 0;
+
+ /* Connect port to previously configured FIFO queue */
+ ret = rte_event_port_link(id, ports[1], &link, 1);
+ if (ret != 1) {
+ printf("%d: failed here\n", __LINE__);
+ goto fail;
+ }
+
+ link.queue_id = queues[0];
+ link.priority = 0;
+
+ /* Attempt to connect to scheduled queue as well */
+ ret = rte_event_port_link(id, ports[1], &link, 1);
+ if (ret == 1) {
+ printf("%d: failed here\n", __LINE__);
+ goto fail;
+ }
+
+ /* link to 2nd queue, enabling start() to pass later */
+ link.queue_id = queues[1];
+ link.priority = 0;
+ ret = rte_event_port_link(id, ports[1], &link, 1);
+ if (ret == 1) {
+ printf("%d: failed here\n", __LINE__);
+ goto fail;
+ }
+
+ api_ut_status[EVENTDEV_API_UT_012].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_012].status = TC_FAILED;
+ return 1;
+}
+
+static int test_EVENTDEV_API_UT_014_rte_event_dev_stop(void)
+{
+ int8_t id;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ return 1;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ rte_event_dev_stop(id);
+
+ api_ut_status[EVENTDEV_API_UT_014].status = TC_PASSED;
+ return 0;
+}
+
+static int test_EVENTDEV_API_UT_015_rte_event_dev_close(void)
+{
+ int8_t id;
+ int ret;
+
+ if (!api_ut_status[EVENTDEV_API_UT_004].executed)
+ test_EVENTDEV_API_UT_004_rte_event_dev_configure();
+ if (api_ut_status[EVENTDEV_API_UT_004].status == TC_FAILED)
+ goto fail;
+
+ id = rte_event_dev_get_dev_id("evdev_sw0");
+
+ ret = rte_event_dev_close(id);
+ if (ret != 0)
+ goto fail;
+
+ api_ut_status[EVENTDEV_API_UT_015].status = TC_PASSED;
+ return 0;
+
+fail:
+ api_ut_status[EVENTDEV_API_UT_015].status = TC_FAILED;
+ return 1;
+}
+
+static int
+test_setup(void)
+{
+ return 0;
+}
+
+static struct unit_test_suite eventdev_test_suite = {
+ .setup = test_setup,
+ .suite_name = "Eventdev Test Suite",
+ .unit_test_cases = {
+ /* device aquisition and config */
+ TEST_CASE(test_EVENTDEV_API_UT_001_rte_event_dev_count),
+ TEST_CASE(test_EVENTDEV_API_UT_002_rte_event_dev_get_dev_id),
+ TEST_CASE(test_EVENTDEV_API_UT_003_rte_event_dev_info_get),
+ TEST_CASE(test_EVENTDEV_API_UT_004_rte_event_dev_configure),
+ /* queue config */
+ TEST_CASE(test_EVENTDEV_API_UT_005_rte_event_queue_count_pre),
+ TEST_CASE(test_EVENTDEV_API_UT_006_rte_event_queue_setup),
+ TEST_CASE(test_EVENTDEV_API_UT_007_rte_event_queue_count_post),
+ /* port config */
+ TEST_CASE(test_EVENTDEV_API_UT_008_rte_event_port_count_pre),
+ TEST_CASE(test_EVENTDEV_API_UT_009_rte_event_port_setup),
+ TEST_CASE(test_EVENTDEV_API_UT_010_rte_event_port_count_post),
+ TEST_CASE(test_EVENTDEV_API_UT_012_rte_event_port_link),
+ TEST_CASE(test_EVENTDEV_API_UT_011_rte_event_dev_start),
+ /* device cleanup */
+ TEST_CASE(test_EVENTDEV_API_UT_014_rte_event_dev_stop),
+ TEST_CASE(test_EVENTDEV_API_UT_015_rte_event_dev_close),
+ TEST_CASES_END()
+ }
+};
+
+static int
+test_eventdev_unit(void)
+{
+ return unit_test_suite_runner(&eventdev_test_suite);
+}
+
+REGISTER_TEST_COMMAND(eventdev_unit_autotest, test_eventdev_unit);